Is deinit Guaranteed to be Called When the Program Finishes? - swift

I have the following code:
class Problem{
init(){
print("Problem init");
}
deinit{
print("Problem deinit");
}
}
var list = Problem();
The output:
Problem init
The following causes the program to call deinit:
class Problem{
init(){
print("Problem init");
}
deinit{
print("Problem deinit");
}
}
do {
var list = Problem();
}
Questions:
Why isn't deinit called the first time?
Is there a way to guarantee that deinit will always be called for Problem in code that I have not control of how it is written(i.e., user code)?
P.S. I know there is most likely an obvious reason that I, as a programmer that is new to Swift, have overlooked.

It is because of the difference in Scopes between these two example that you create by adding the do-block.
In the first scenario, when that code is ran, an instance of Problem is created (initialized) at a Global Scope (outside of a class or struct definition in Swift) and then it just sits there. The program does not end and it is never de-initialized.
In the second scenario, you create the instance of Problem inside a the do-block, so it's scope is limited to inside that block. When the do-block ends, the instance is dereferenced, and thus de-initialized.

Related

Swift 4 retain cycle different from swift 3? [duplicate]

In the next code I'm trying to call the deinit method releasing all the references to the Person Class instance Mark but the deinit is never called. Why?
class Person{
let name:String
init(name:String){
self.name = name
println("Person created")
}
deinit {
println("Person \(name) deinit")
}
}
var Mark:Person? = Person(name:"Mark")
Mark = nil // Shouldn't the person deinit method be called here? It doesn't.
Xcode's Playgrounds for Swift don't work like regular apps; they aren't being run just once. The objects created stay in memory and can be inspected until you change the code, at which point the whole playground is reevaluated. When this happens, all previous results are discarded and while all object will be deallocated, you won't see any output from that.
Your code is correct, but Playgrounds is not suited to test things related to memory management.
Here's a related SO question: Memory leaks in the swift playground / deinit{} not called consistently
Deinit will called if create object like this
_ = Person(name:"Mark")
Deinit gets called when you ignore the variable like so.
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
_ = Owner()
PlaygroundPage.current.finishExecution()
Owner class -
public class Owner {
public var car: Car?
public init (_ car: Car? = nil) {
self.car = car
print ("Owner got allocated")
}
deinit {
print ("owner got deallocated")
}
}
// Prints -
Owner got allocated
owner got deallocated
workaround - move all variable initialisation code into a function and call that function.
Playground having issues used to be a problem. For 99% of the memory management cases they work just like a normal project. Playground has improved A LOT over time.
Such a problem should no longer exist and Playground can be used reliably.

CLKComplicationServer initializes an already initialized singleton class CLKComplicationDataSource, although init() is private

To update complications on the watch, I use a singleton class ComplicationController (irrelevant code has been omitted below):
final class ComplicationController: NSObject, CLKComplicationDataSource {
static let shared = ComplicationController() // Instantiate the singleton
private override init() {
super.init()
print("====self: \(self): init")
} // Others can't init the singleton
}
The singleton is created on the watch by the extension delegate:
class ExtensionDelegate: NSObject, WKExtensionDelegate {
override init() {
super.init()
_ = ComplicationController.shared
}
}
When I launch the watch extension with a breakpoint at the print statement above, the execution breaks and the stack trace is:
When I then execute the print statement in a single step, the debugger shows:
====self: <Watch_Extension.ComplicationController: 0x7bf35f20>: init
When I then continue, the execution breaks again at the same breakpoint, and the stack trace is:
After another single step, the debugger shows:
====self: <Watch_Extension.ComplicationController: 0x7d3211d0>: init
Obviously, the CLKComplicationServer has created another instance of the singleton.
My question is: Did I something wrong or is this a bug? If it is a bug, is there a workaround?
PS: It does not help not to initialize ComplicationController in the ExtensionDelegate. In this case, the 2nd instance is created as soon as ComplicationController.shared is used anywhere in the code.
I found a workaround:
Do not instantiate the singleton in the app, i.e. do not use ComplicationController.shared anywhere.
If you have to call functions in ComplicationController.shared, send a notification, e.g. to the default notification center.
The ComplicationController singleton had to have registered for such notifications, and when it receives one, it has to execute the required function.
This did work for me.

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.

Does setting an optional instance to nil call deinit (if implemented)? [duplicate]

In the next code I'm trying to call the deinit method releasing all the references to the Person Class instance Mark but the deinit is never called. Why?
class Person{
let name:String
init(name:String){
self.name = name
println("Person created")
}
deinit {
println("Person \(name) deinit")
}
}
var Mark:Person? = Person(name:"Mark")
Mark = nil // Shouldn't the person deinit method be called here? It doesn't.
Xcode's Playgrounds for Swift don't work like regular apps; they aren't being run just once. The objects created stay in memory and can be inspected until you change the code, at which point the whole playground is reevaluated. When this happens, all previous results are discarded and while all object will be deallocated, you won't see any output from that.
Your code is correct, but Playgrounds is not suited to test things related to memory management.
Here's a related SO question: Memory leaks in the swift playground / deinit{} not called consistently
Deinit will called if create object like this
_ = Person(name:"Mark")
Deinit gets called when you ignore the variable like so.
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
_ = Owner()
PlaygroundPage.current.finishExecution()
Owner class -
public class Owner {
public var car: Car?
public init (_ car: Car? = nil) {
self.car = car
print ("Owner got allocated")
}
deinit {
print ("owner got deallocated")
}
}
// Prints -
Owner got allocated
owner got deallocated
workaround - move all variable initialisation code into a function and call that function.
Playground having issues used to be a problem. For 99% of the memory management cases they work just like a normal project. Playground has improved A LOT over time.
Such a problem should no longer exist and Playground can be used reliably.

Deinit method is never called - Swift playground

In the next code I'm trying to call the deinit method releasing all the references to the Person Class instance Mark but the deinit is never called. Why?
class Person{
let name:String
init(name:String){
self.name = name
println("Person created")
}
deinit {
println("Person \(name) deinit")
}
}
var Mark:Person? = Person(name:"Mark")
Mark = nil // Shouldn't the person deinit method be called here? It doesn't.
Xcode's Playgrounds for Swift don't work like regular apps; they aren't being run just once. The objects created stay in memory and can be inspected until you change the code, at which point the whole playground is reevaluated. When this happens, all previous results are discarded and while all object will be deallocated, you won't see any output from that.
Your code is correct, but Playgrounds is not suited to test things related to memory management.
Here's a related SO question: Memory leaks in the swift playground / deinit{} not called consistently
Deinit will called if create object like this
_ = Person(name:"Mark")
Deinit gets called when you ignore the variable like so.
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
_ = Owner()
PlaygroundPage.current.finishExecution()
Owner class -
public class Owner {
public var car: Car?
public init (_ car: Car? = nil) {
self.car = car
print ("Owner got allocated")
}
deinit {
print ("owner got deallocated")
}
}
// Prints -
Owner got allocated
owner got deallocated
workaround - move all variable initialisation code into a function and call that function.
Playground having issues used to be a problem. For 99% of the memory management cases they work just like a normal project. Playground has improved A LOT over time.
Such a problem should no longer exist and Playground can be used reliably.