When should I use deinit?
It's not required that you implement that method, but you can use it if you need to do some action or cleanup before deallocating the object.
The Apple docs include an example:
struct Bank {
static var coinsInBank = 10_000
static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receiveCoins(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.vendCoins(coins)
}
func winCoins(coins: Int) {
coinsInPurse += Bank.vendCoins(coins)
}
deinit {
Bank.receiveCoins(coinsInPurse)
}
}
So whenever the player is removed from the game, its coins are returned to the bank.
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,deinit
is called significantly later,
long after last reference gets out of scope (whenautorelease
pool is drained). - And when App is terminating,
deinit
is guaranteed to never get called!?
(ifdeinit
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 tonil
(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, 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 are called during program termination,
since that is required by C++
spec,
but that's all and 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).
Deinit is it a good practice to implement it on viewControllers?
By default, you don't have to implement the deinit
method in your classes:
Swift automatically deallocates your instances when they are no longer
needed, to free up resources. Swift handles the memory management of
instances through automatic reference counting (ARC), as described in
Automatic Reference Counting. Typically you don’t need to perform
manual cleanup when your instances are deallocated. However, when you
are working with your own resources, you might need to perform some
additional cleanup yourself. For example, if you create a custom class
to open a file and write some data to it, you might need to close the
file before the class instance is deallocated.Swift Deinitialization Documentation - How Deinitialization Works Section.
Usually, when working with View Controllers it seems that there is no need to do such an implementation. However, as mentioned in @rmaddy's comment, it is still an approach for tracing memory leak or reference cycle with the view controller.
If your purpose is to check if the controller has been removed from the hierarchy (view controller life cycle), you could implement viewWillDisappear(_:) or viewDidDisappear(_:) methods; Note that calling on of these methods does not guarantees that the deinit
will be called, i.e it does not mean that disappearing the view controller always leads to deallocate it (related: Deinit never called, explanation for deinit not called).
Also:
these Q&As should be useful:
When should I use deinit?
how to make deinit take effect in swift
Understand deinitialization and inheritance in swift language
how to make deinit take effect in swift
class Car {
static var population: Int = 0
init() {
Car.population += 1
}
deinit {
Car.population -= 1
}
}
var cars: [Car] = [Car(), Car()]
print("Population:", Car.population) // "Population: 2"
// now the second car is removed from array and we have no other references to it
// it gets removed from memory and deinit is called
cars.removeLast()
print("Population:", Car.population) // "Population: 1"
However, the same can be achieved just by asking the number of items in cars
array. And that's usually a better alternative than a private counter of instances.
To keep the items in memory you will always need some kind of register (e.g. an array) for them. And that register can keep them counted.
One possibility:
class CarPopulation {
var liveCars: [Car] = []
var junkCars: [Car] = []
}
Or you can keep them in one array and set junk
on the car and count non-junk cars when needed:
class CarPopulation {
var cars: [Car] = []
func liveCars() -> Int {
return self.cars.filter { !$0.junk }.count
}
}
There are many possibilities but extracting the counters to some other class that owns the cars is probably a better solution.
Should deinit be overridden to remove observers in Swift?
As of iOS 9 , you don't need to remove observers yourself, if you're not using block based observers though. The system will do it for you, since it uses zeroing-weak references for observers, where it can.
If the observer is able to be stored as a zeroing-weak reference the
underlying storage will store the observer as a zeroing weak
reference, alternatively if the object cannot be stored weakly (i.e.
it has a custom retain/release mechanism that would prevent the
runtime from being able to store the object weakly) it will store the
object as a non-weak zeroing reference. This means that observers are
not required to un-register in their deallocation method.Block based observers via the -[NSNotificationCenter
addObserverForName: object: queue: usingBlock] method still need to be
un-registered when no longer in use since the system still holds a
strong reference to these observers.
Apple Docs
and for super.deinit() apple says
Deinitializers are called automatically, just before instance
deallocation takes place. You are not allowed to call a deinitializer
yourself. Superclass deinitializers are inherited by their subclasses,
and the superclass deinitializer is called automatically at the end of
a subclass deinitializer implementation. Superclass deinitializers are
always called, even if a subclass does not provide its own
deinitializer.
swift docs
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.
Why don't structs have deinitializers in Swift like classes?
deinit
is for reference types (see https://stackoverflow.com/a/27366050/341994 for what that means) where the object pointed to persists independently until a reference count drops to zero.
A struct is a value type and does not require memory management that would need a deinit
. Structs are not independently persistent the way classes are. Merely setting a property of a struct destroys it and replaces it. Assigning a struct copies it. Structs are created and destroyed in a highly lightweight way. They don’t need to signal their destruction; they are too lightweight for that.
Is cleaning up strong references in deinit a correct pattern?
This statement
[...] that recommend removing an observer from the NotificationCenter in the deinit of the UIViewController [...]
was true in the past.
And your statement
[...] if there still is a strong reference to the class, deinit will not get called.
is correct.
Observers have weak reference
An observer holds a weak reference
to the target object.
This explain why the deinit
of an object will be called even if there are multiple active observers.
So why do we want to remove the observers in the deinit?
This was needed prior to iOS 9 to prevent an observer from invoking a method of a deallocated object.
However unregistering an observer is no longer needed from macOS 10.11 and iOS 9.0
In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated.
Source
Swift - self in deinit method
In 90% of cases you have to use self
in deinit
. Both in Swift and Objective-C.
That's actually the whole point of that method - the last chance to access that object before deallocation.
What you should avoid is storing self
to another object from deinit
, not accessing self
.
Also, in Objective-C some people try to avoid using property setters and getters in init
and dealloc
to avoid dangerous side-effects that might be hidden in them, and they are accessing ivars directly instead (_prop = nil
instead of self.prop = nil
). That's actually impossible in Swift because there are no ivars. However, Swift is much safer in that regard. Note that _prop = nil
in Objective-C still accesses self
. It's just a short syntax for self->_prop = nil
. We are avoiding properties, not self
.
Related Topics
Uibarbuttonitem Selector Not Working
Why Is the Alert Triggering Out of Order If Value Is Not Updated
How Do Generators Whose Element Is Optional Know When They'Ve Reached the End
How to Say "If X == a or B or C" as Succinctly in Swift as Possible
Pdfview Does Not Display My PDF
Callkit - How to Bring the Cxcallcontroller to the Front
No Value Associated with Key Codingkeys While Trying to Get Data from Github API in Xcode App
What Is the Type of the Logical Operators
Subtle Cast Warning When Using SQLite.Swift ... Binding? to Any
In Swift,There's No Way to Get the Returned Function's Argument Names
How to Transfer the User's Score to Another Scene in Swift and Spritekit
"Cgfloat Is Not Convertible to Int" When Trying to Calculate an Expression
How to Implement Protocol Methods That Return Covariant Selfs
Nsdatecomponents Weekofyear Returns Wrong Date
Using Applescript with Apple Events in MACos - Script Not Working