Defer statement at the end of deinit produces a warning - swift

Since the Xcode 10.2 (Swift 5) the defer statement at the end of the deinit scope produces:
'defer' statement before end of scope always executes immediately; replace with 'do' statement to silence this warning
Let's take a look at this example:
var foo: String {
didSet {
// smt
}
}
deinit {
defer { <--- Warning
foo = bar
}
}
Of course it's possible to get rid of this warning by moving the code from the observer to a method and call it explicitly but…
What's the point of this warning? - Isn't it reasonable to have the defer statement in the deinit? (e.g. to be able to trigger properties' observers).

The warning is correct in that the use of defer here doesn't change the order of execution of your program, which is what the statement is designed for. It is however unfortunate that the suggested replacement otherwise changes the behaviour of your program (filed a bug: SR-10207).
It's worth noting that the use of defer to trigger a property observer is a bit of a hack that only works because the type checker considers it to be a different context to the deinit body. You can also achieve the same result with a closure expression:
deinit {
{ foo = bar }()
}
Ideally, there would be some form of syntax that lets you tell Swift "don't perform a direct-to-storage access here", so that such workarounds aren't necessary, but there isn't currently.
A less hacky workaround is to pull out the desired logic of the deinitialiser into a separate method, which puts the logic in a context where property accesses are done normally:
class C {
var bar = ""
var foo: String {
didSet {
// smt
}
}
init(foo: String) { self.foo = foo }
private func doDeinit() {
foo = bar
}
deinit {
doDeinit()
}
}

Related

Implicitly unwrapped optional var destroyed by compiler before end of scope?

With swift compiler optimizations implicitly unwrapped optional variables do not survive the whole scope, but are released immediately after usage.
Here is my environment:
swift --version
outputs
Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin20.2.0
Xcode version is Version 12.3 (12C33)
Consider this most rudimentary example that shows the issue:
final class SomeClass {
func doSth() {}
deinit {
print("deinit")
}
}
func do() {
var someObject: SomeClass! = SomeClass()
someObject.doSth()
print("done")
}
This should ouput
done
deinit
However, in release builds (with Swift code optimizations enabled "-O") it prints the other way round:
deinit
done
This is ONLY the case for var someObject: SomeClass!.
The following alterations of that code ALL output correctly (meaning the Object is released when the scope of the function is left):
Define var as constant:
func doSthSpecial() {
let someObject: SomeClass! = SomeClass()
someObject.doSth()
print("done")
}
Define var as optional explicitly:
func doSthSpecial() {
var someObject: SomeClass? = SomeClass()
someObject.doSth()
print("done")
}
Access like an optional:
func doSthSpecial() {
var someObject: SomeClass! = SomeClass()
someObject?.doSth()
print("done")
}
These last three implementations all output
done
deinit
in that order.
Somehow this leaves me speechless 🤷‍♂️.
I understand this optimization, it makes sense. But as a programmer we are used to local variables inside of functions being available until leaving the scope.
The problem I have here is about the lifetime of an object that is stored in such an implicitly unwrapped optional variable. If I have code that depends on the lifetime of this object (which is the case with RxSwift and its DisposeBags for example) then I am getting weird behavior, unexpected behavior!
I could consider this as a bug in Swift, but what do you think? Bug or no bug?
Here is a more real-world scenario with RxSwift where you could be using such a construct:
import UIKit
import RxSwift
final class SomeClass {
func doSth() {}
deinit {
print("deinit")
}
}
class ViewController: UIViewController {
let providePassword = PublishSubject<String>()
lazy var askForPassword: Observable<String> = {
return Observable.create { observer in
_ = self.providePassword.subscribe(observer)
return Disposables.create()
}
.debug(">>> ask for password signal")
}()
private func performAsyncSyncTask() {
DispatchQueue.global().async {
var disposeBag: DisposeBag! = DisposeBag()
let sema = DispatchSemaphore(value: 0)
self.askForPassword
.subscribe(onNext: { pw in
print(pw)
sema.signal()
})
.disposed(by: disposeBag)
_ = sema.wait(timeout: DispatchTime.distantFuture)
disposeBag = nil
}
}
#IBAction func startAskPassword(sender: AnyObject) {
self.performAsyncSyncTask()
}
#IBAction func sendPassword(sender: AnyObject) {
self.providePassword.on(.next("hardcoded pw"))
}
}
The problem here is: When executing self.performAsyncSyncTask() it is subscribed to askForPassword but because in optimized builds the implicitly unwrapped optional variable is purged immediately after using it in .disposed(by: disposeBag).
This destroys the signal immediately after subscribing to it.
But as a programmer we are used to local variables inside of functions being available until leaving the scope.
This hasn't been the case since ARC was first released for ObjC. ARC has always had the option to release objects after their last use (and very often makes use of this). This is by design, and is not a bug in Swift (or in ObjC, where it's also true).
In Swift, if you want to extend the lifetime of an object beyond its last use,withExtendedLifetime is explicitly for this purpose.
var someObject: SomeClass! = SomeClass()
withExtendedLifetime(someObject) {
someObject.doSth()
print("done")
}
Keep in mind that it is legal for objects to have balanced retain/autorelease calls on them, which may cause them to outlive their scope as well. This is much less common in Swift, but still legal and happens if you pass a Swift object to ObjC (which can happen in many places you may not expect).
You should be very careful relying on when deinit will be called. It can surprise you, and isn't even promised in all cases (for example, deinit is not called during program quit on Mac, which tends to surprise C++ developers).
IMO performAsyncSyncTask is a dangerous pattern, and should be redesigned with clearer ownership. I don't do enough RxSwift work to immediately redesign it, but blocking the whole thread on a DispatchSemaphore seems the wrong way to integrate with any reactive system. Threads are a finite resource, and this forces the system to create more while this one is blocked doing nothing.

Capture a method weakly

Note: This question is basically the same as this one, but for Swift 4 or 5.
Say I have a class that captures a closure:
class CallbackHolder {
typealias Callback = (String) -> Void
var callback: Callback
init(_ callback: #escaping Callback) {
self.callback = callback
}
func useCallback() {
self.callback("Hi!")
}
}
This class simply holds a callback in a variable, and has a function that uses that callback.
Now, say I have a client class that owns such a callback holder. This class wants the callback holder to call one of its methods as the callback:
class Client {
func callback(string: String) {
print(string)
}
lazy var callbackOwner = CallbackOwner(callback: callback)
deinit {
print("deinit")
}
}
This class has a callback, a callback owner that calls that callback, and a deinit that prints something so that we know whether we have a retain cycle (no deinit = retain cycle).
We can test our setup with the following test function:
func test() {
Client().callbackOwner.useCallback()
}
We want the test function to print both Hi! and deinit, so that we know that the callback works, and that the client does not suffer from a retain cycle.
The above Client implementation does in fact have a retain cycle -- passing the callback method to the callback owner causes the owner to retain the client strongly, causing a cycle.
Of course, we can fix the cycle by replacing
lazy var callbackOwner = CallbackOwner(callback: callback)
with
lazy var callbackOwner = CallbackOwner(callback: { [weak self] in
self?.callback($0)
})
This works, but:
it is tedious (compare the amount of code we now need)
it is dangerous (every new client of my CallbackOwner class must remember to do it this way, even though the original way is completely valid syntax, otherwise they will get a retain cycle)
So I am looking for a better way. I would like to capture the callback weakly at the CallbackOwner, not at the client. That way, new clients don't have to be aware of the danger of the retain cycle, and they can use my CallbackOwner in the most intuitive way possible.
So I tried to change CallbackOwner's callback property to
weak var callback: Callback?
but of course, Swift only allows us to capture class types weakly, not closures or methods.
At the time when this answer was written, there did not seem to be a way to do achieve what I'm looking for, but that was over 4 years ago. Has there been any developments in recent Swift versions that would allow me to pass a method to a closure-capturing object without causing a retain cycle?
Well one obvious way to do this would be to not hold a reference to CallbackHolder in Client i.e.
class Client {
func callback(string: String) {
print(string)
}
var callbackOwner: CallbackHolder { return CallbackHolder(callback) }
deinit {
print("deinit")
}
}
In the above case, I'd probably make CallbackHolder a struct rather than a class.
Personally, I don't see any value in wrapping the callback in a class at all. Just pass the callback around, or even Client. Maybe make a protocol for it to adhere to
protocol Callbackable
{
func callback(string: String)
}
extension Callbackable
{
func useCallback() {
self.callback(string: "Hi!")
}
}
class Client: Callbackable {
func callback(string: String) {
print(string)
}
deinit {
print("deinit")
}
}
func test(thing: Callbackable) {
thing.useCallback()
}
test(thing: Client())

Swift function can be called only once

What is the simplest way to write a piece of code that can be executed only once?
I know a way but has a problem.
first, I write a Boolean variable that has negative value but can be set to positive and cannot change after that
var hasTheFunctionCalled : Bool = false {
didSet{
hasTheFunctionCalled = true
}
}
and then write the function and the code inside it:
func theFunction(){
if !hasTheFunctionCalled{
//do the thing
}
hasTheFunctionCalled = true
}
but the problem is that the variable can be changed from somewhere else in the scope and this solution doesn't really look so simple and concrete.
A simple solution is to take advantage of lazy variables in the following way:
// Declare your "once-only" closure like this
private lazy var myFunction: Void = {
// Do something once
}()
...
// Then to execute it, just call
_ = myFunction
This ensures that the code inside the myFunction closure is only executed the first time that the program runs _ = myFunction
Edit: Another approach is to use so called "dispatch once tokens". This comes from Objective-C and was available in Swift until Swift 3. It is still possible to make it work, however you will need to add a little bit of custom code. You can find more information on this post -> dispatch_once after the Swift 3 GCD API changes
Edit2: Should be _ = myFunction and not _ = myFunction(), as JohnMontgomery pointed out.
You might use a static bool inside a struct nested into the function itself doing so:
func theFunction(){
struct Holder { static var called = false }
if !Holder.called {
Holder.called = true
//do the thing
}
}
One possible technique is to put the code into the initializer of a static type property, which is guaranteed to be lazily initialized only once (even when accessed across multiple threads simultaneously):
func theFunction() {
struct Once {
static let once = Once()
init() {
print("This should be executed only once during the lifetime of the program")
}
}
_ = Once.once
}
(Compare Singleton in the "Using Swift with Cocoa and Objective-C" reference.)
Example:
print("Call #1")
theFunction()
print("Call #2")
theFunction()
print("Done")
Output:
Call #1
This should be executed only once during the lifetime of the program
Call #2
Done
You can do smth like:
class Once {
var already: Bool = false
func run(#noescape block: () -> Void) {
guard !already else { return }
block()
already = true
}
}
and than use it like
class ViewController: UIViewController {
let once = Once()
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
once.run {
cameraMan.setup()
}
}
}
ref: https://dev.to/onmyway133/how-to-run-action-once-in-swift-3k7o
Depending on what you are doing inside your method : you may check if the end result has already been accomplished :
e.g. if you instantiate a class, check if it is different from nil
You can also use UserDefaults, and the knowledge that the default UserDefault Bool is false:
if !UserDefaults.standard.bool(forKey: "ExecuteOnce") {
func()
UserDefaults.standard.set(true, forKey: "ExecuteOnce")
}
This code will execute exactly once.

Difference using deinit and defer for resource deallocation in Swift

I'm learning more about Swift and came across the defer statement recently, which seems really intriguing to me. However I don't really understand it's purpose. Coming from C++ I would have implemented the same functionality using deallocation function and as a matter of fact, as Swift is ARC, it can do the same.
Let's say FooData and BarData both work with data that needs to deallocated.
class FooData {
deinit {
print("FooData being deallocated")
}
}
class BarData {
}
func baz() -> Int {
var a = FooData()
var b = BarData()
defer { print("BarData being deallocated") }
/* sensitive operations that could throw at any time */
return 0
}
baz()
// BarData being deallocated
// FooData being deallocated
So what's the advantage of the defer approach over the deinit approach? Just thinking about using defer for anything besides resource cleanup makes my head hurt...
You are seeing as different but there are not, defer was introduced by Apple as a safe and easy way to handle the clean up before returning, but defer only works for scopes. So let me explain better, if you have some scope defined inside a function an the variable you have created exist only inside the scope you cannot access from the deinit, for example:
func resizeImage(url: NSURL) -> UIImage? {
// ...
let dataSize: Int = ...
let destData = UnsafeMutablePointer<UInt8>.alloc(dataSize)
defer {
destData.dealloc(dataSize)
}
var destBuffer = vImage_Buffer(data: destData, ...)
// scale the image from sourceBuffer to destBuffer
var error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, ...)
guard error == kvImageNoError
else { return nil }
// create a CGImage from the destBuffer
guard let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, ...)
else { return nil }
// ...
}
In this case it doesn't make sense define the variable destData as global and we need to deallocate once we finish of work with it, so defer it's the choice.
I think deinit it can be used for more global scope, for example when you implement the Key-Value Observer using NSNotificationCenter or something else you need.
I hope this help you.
Using defer inside a method means that its work will be executed as the method is exiting.
override func viewDidLoad() {
super.viewDidLoad()
print("Step 1")
myFunc()
print("Step 5")
}
func myFunc() {
print("Step 2")
defer { print("Step 3") }
print("Step 4")
}
"Step 1", "Step 2", "Step 4", "Step 3", "Step 5" – steps 3 and 4 are switched because 3 is deferred until the myFunc() method ends, i.e. when it goes out of scope programmatically.
About deinit, this is used to run code before deinitialization. The deinit code is run automatically. Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself.
class Item {
init() {
print("init called")
}
deinit {
// Called whenever class stops existing.
print("deinit called")
}
}
// Create optional Item variable.
var i: Item? = Item()
// Set optional to nil to force deinit.
i = nil
In programming some functions always appear in pairs. For example, opening a connection and closing that connection, locking a mutex and unlocking a mutex, incrementing a counter, decrementing a counter, allocating memory, deallocating memory.
The pattern usually looks like this:
lock()
... do something ...
unlock()
The middle part can be complicated and long. There can be returns (e.g. for failed preconditions and Swift recommends this pattern with its guard). Sometimes it's very hard not to forget to include that unlock() in all execution paths.
One way to solve the situation nicely is using a helper function:
func doSomething() {
... do something with returns ...
}
lock()
doSomething()
unlock()
but that's not always possible, e.g. when you have several nested objects.
In C the same pattern was often solved with goto:
x = malloc(...);
y = malloc(...);
if (!precondition) {
goto end;
}
... some code ...
end:
free(y);
free(x);
Modern languages came with a better approach which in Swift is implemented using defer (you can also find defer in Go, for example).
lock()
defer {
unlock()
}
... some code ...
This approach has several benefits:
You can have the calls together, which increases readability and makes it very hard to forget the second call.
All returns, precondition checks, error handling will leave the code in correct state because unlock will be always called correctly. This is similar to finally in exception handling in Java (and other languages)
If you are asking about the difference from deinit, it works in a similar way. However defer can work in functions while deinit works only for classes.
Also note that you could reimplement defer using deinit but the usage would be more complicated and the behavior less predictable.
defer could be called conditionally what is impossible to implement with deinit
var i = 1
func foo()->Int {
if i == 1 {
defer {
i = 0
}
}
return i + 1
}
print("foo:", foo(), "i:", i)
Consider a database transaction. You want to close the connection when you're done, but you want to keep the object around to reinstate connections in the future:
stuct foo {
let db = Database()
func useDatabase() throws {
let connection = db.openConnection()
defer {
// close conenction, but keep db around for future use
connection.close
}
try connection.thisCanThrow()
}
}
This is just one example, but there are many like it. In particular, a lot of cases arise where you want to model the restricted lifespan of a state, without binding it tightly to an object's life time.
C++ heavily relies on RAII. Swift is certainly capable of adhering to the same paradigm, but it can also go beyond it with defer.

How do I execute code once and only once in Swift?

The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once is of no use if we I can change the value of token! And turning token into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>.
So should we give up on dispatch_once in Swift? Is there a safer way to execute code just once?
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
Static properties initialized by a closure are run lazily and at most once, so this prints only once, in spite of being called twice:
/*
run like:
swift once.swift
swift once.swift run
to see both cases
*/
class Once {
static let run: Void = {
print("Behold! \(__FUNCTION__) runs!")
return ()
}()
}
if Process.arguments.indexOf("run") != nil {
let _ = Once.run
let _ = Once.run
print("Called twice, but only printed \"Behold\" once, as desired.")
} else {
print("Note how it's run lazily, so you won't see the \"Behold\" text now.")
}
Example runs:
~/W/WhenDoesStaticDefaultRun> swift once.swift
Note how it's run lazily, so you won't see the "Behold" text now.
~/W/WhenDoesStaticDefaultRun> swift once.swift run
Behold! Once runs!
Called twice, but only printed "Behold" once, as desired.
I think the best approach is to just construct resources lazily as needed. Swift makes this easy.
There are several options. As already mentioned, you can initialize a static property within a type using a closure.
However, the simplest option is to define a global variable (or constant) and initialize it with a closure then reference that variable anywhere the initialization code is required to have happened once:
let resourceInit : Void = {
print("doing once...")
// do something once
}()
Another option is to wrap the type within a function so it reads better when calling. For example:
func doOnce() {
struct Resource {
static var resourceInit : Void = {
print("doing something once...")
}()
}
let _ = Resource.resourceInit
}
You can do variations on this as needed. For example, instead of using the type internal to the function, you can use a private global and internal or public function as needed.
However, I think the best approach is just to determine what resources you need to initialize and create them lazily as global or static properties.
For anyone who stumbles on this thread... We ran into a similar situation at Thumbtack and came up with this: https://www.github.com/thumbtack/Swift-RunOnce. Essentially, it lets you write the following
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
runOnce {
// One-time code
}
}
I also wrote a blog post explaining how the code works, and explaining why we felt it was worth adding to our codebase.
I found this while searching for something similar: Run code once per app install. The above solutions only work within each app run. If you want to run something once across app launches, do this:
func runOnce() {
if UserDefaults.standard.object(forKey: "run_once_key") == nil {
UserDefaults.standard.set(true, forKey: "run_once_key")
/* run once code */
} else {
/* already ran one time */
}
}
If the app is deleted and re-installed, this will reset.
Use NSUbiquitousKeyValueStore for tracking a value across installs and devices as long as user using same appleID.