How to Call Deinit in Swift

How to call deinit in Swift

The problem is that a playground is not real life. This is just one more reason for not using them (I think they are a terrible mistake on Apple's part). Use a real iOS app project and deinit will be called as expected.

Example from a real project:

class ViewController: UIViewController {
class Person{
let name:String;
init(name:String){
self.name = name;
println("\(name) is being initialized.");
}
deinit{
println("\(name) is being deInitialized.");

}
}
override func viewDidLoad() {
super.viewDidLoad()
var person:Person?;
person = Person(name:"leo");
person = nil;
}
}

That does what you expect it to do.

how to call deinit method within class definition in swift

You can create a protocol which does the self destruction based on a certain criteria. Here's an example using a class

class SelfDestructorClass
{
var calledTimes = 0
let MAX_TIMES=5
static var instancesOfSelf = [SelfDestructorClass]()

init()
{
SelfDestructorClass.instancesOfSelf.append(self)
}

class func destroySelf(object:SelfDestructorClass)
{
instancesOfSelf = instancesOfSelf.filter {
$0 !== object
}
}

deinit {
print("Destroying instance of SelfDestructorClass")
}

func call() {
calledTimes += 1
print("called \(calledTimes)")
if calledTimes > MAX_TIMES {
SelfDestructorClass.destroySelf(self)
}
}
}

You can derive your class from this class and then call call() on those object. The basic idea is to have the ownership of the object at one and only one place only and then detach the ownership when the criteria is met. The ownership in this case is a static array and detaching is removing it from the array. One important thing to note is that you have to use weak reference to the object wherever you are using it.

E.g.

class ViewController: UIViewController {

weak var selfDestructingObject = SelfDestructorClass()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

@IBAction func countDown(sender:AnyObject?)
{
if selfDestructingObject != nil {
selfDestructingObject!.call()
} else {
print("object no longer exists")
}
}
}

When is `deinit` exactly called? (in Swift)

The deinit is intended to release resources (such as freeing memory that is not under ARC).

(Thanks to Martin
and Rob's input, we can conclude below)

When is deinit called?

Usually, when last strong-reference gets out of scope,
deinit is called instantly (then deallocation happens).

  • But if affected by autorelease feature (which has conditions), deinit is called significantly later,
    long after last reference gets out of scope (when autorelease pool is drained).
  • And when App is terminating, deinit is guaranteed to never get called!?
    (if deinit was not already called).
  • Also in extremely common cases, deinit is called before strong-ref-variable's scope ends:
    • In Swift unlike other languages, when we set a weak-reference equal to a strong-reference,
      it could result to nil (which is absolutely allowed by Swift).

    • This happens if compiler detects that the remaining lines of scope,
      have NOT any strong-reference.

    • Possible workaround is using withExtendedLifetime(_:_:) global-method / function, like:

    withExtendedLifetime(myStrongRefVariable) {
    // Do something that only needs non-nil weak reference.
    }

Is it like C++ destructor?

There is no equivalent of a C++ destructor in ObjC or Swift.

(Objective-C++ object's destructor (dealloc) are called during program termination,
because that is required by C++ spec,
but that's all and else Obj-C++'s dealloc behavior is same as deinit.)

Is Swift using Garbage-Collector?

No, but whenever autorelease feature affects objects,
the deinit can be postponed (till autorelease-pool is drained, as mentioned above).

ViewController not calling deinit method swift 4

Case 1:

Try writing NotificationCenter.default.removeObserver(self) line in override func viewWillDisappear(_ animated: Bool).
May be notification center retaining you viewController's object.

Case 2:
If you are navigating from you controller using Segue then UIStoryboardSegue retaining you viewController's object as source viewController.
In that case too first case can solve you issue.

deinit not called in specific case

I expect deinit to be called at program termination

You should not expect that. Objects that exist at program termination are generally not deallocated. Memory cleanup is left to the operating system (which frees all of the program's memory). This is a long-existing optimization in Cocoa to speed up program termination.

deinit is intended only to release resources (such as freeing memory that is not under ARC). There is no equivalent of a C++ destructor in ObjC or Swift. (C++ and Objective-C++ objects are destroyed during program termination, since this is required by spec.)

When do ViewControllers call deinit? During move to background? During move to suspended?

When the app is is terminated abruptly (your cases 1 or 2), usually no code is called, including any deinit code. There is no need for deinit becasue all application memory is deallocated at once.

Otherwise, deinit is called when an object is no longer needed and this has nothing to do with external events, whether the app is in the foreground or in the background. It depends only when you, as a programmer, release the ownership of the object (e.g. when you pop a navigation controller or dismiss a presented controller).

Is deinit Guaranteed to be Called When the Program Finishes?

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 Topics



Leave a reply



Submit