dealloc in Swift
deinit {
// perform the deinitialization
}
From the Swift Documentation:
A deinitializer is called immediately before a class instance is
deallocated. You write deinitializers with the deinit keyword, similar
to how intializers are written with the init keyword. Deinitializers
are only available on class types.Typically you don’t need to perform manual clean-up when your
instances are deallocated. However, when you are working with your own
resources, you might need to perform some additional clean-up
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.
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).
Swift: How to deallocate properties when init throw?
I found a solution to my problem.
import XCTest
class Person {
// case1
let pointer1: UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>.allocate(capacity: 1)
// case2
let pointer2: UnsafeMutablePointer<Int>
let name: String
init(name: String) throws {
// deallocate helper for case1
var deallocateHelper1: UnsafeMutablePointer<Int>? = self.pointer1
defer {
deallocateHelper1?.deallocate()
}
// case2
self.pointer2 = UnsafeMutablePointer<Int>.allocate(capacity: 1)
var deallocateHelper2: UnsafeMutablePointer<Int>? = self.pointer2
defer {
deallocateHelper2?.deallocate()
}
// case ...
if name == "UnsupportName" {
throw NSError()
}
self.name = name
// In the end. set deallocate helpers to nil
deallocateHelper1 = nil
deallocateHelper2 = nil
}
deinit {
pointer1.deallocate()
pointer2.deallocate()
}
}
class InterestTests: XCTestCase {
func testExample() {
while true {
_ = try? Person(name: "UnsupportName")
}
}
}
Swift 5 : how to deallocate memory, allocated by shared library
malloc()
ed memory must be released with free()
:
if let dataStr = rxData {
// do something with `dataStr`
// ...
free(dataStr)
}
This is also a good use-case for defer
, which calls the closure just before the scope of the block is left:
if let dataStr = rxData {
defer { free(dataStr) }
// do something with `dataStr`
// ...
}
On Apple platforms, free()
is imported from the standard C library as part of the Darwin
module (which is imported by Foundation
, AppKit
, or UIKit
). On Linux you would import Glibc
.
Deinit not called on a UIViewController, but Dealloc is
TLDR:
Breakpoints will only work in deinit
if there is an executable line of code ahead of them.
- If you place a breakpoint on a line of executable code, then it will work.
- The executable line of code must belong to the
deinit
method.
Thanks to Adam for pointing me in the right direction. I didn't do extensive tests, but it looks like breakpoints behave differently in deinit
than everywhere else in your code.
I will show you several examples where I added a breakpoint on each line number. Those that will work (e.g. pause execution or perform their action such as logging a message) will be indicated via the ➤ symbol.
Normally breakpoints are hit liberally, even if a method does nothing:
➤ 1
➤ 2 func doNothing() {
➤ 3
➤ 4 }
5
However, in a blank deinit
method, NO breakpoints will ever get hit:
1
2 deinit {
3
4 }
5
By adding more lines of code, we can see that it depends on if there is an executable line of code following the breakpoint:
➤ 1
➤ 2 deinit {
➤ 3 //
➤ 4 doNothing()
➤ 5 //
➤ 6 foo = "abc"
7 //
8 }
9
In particular, play close attention to lines 7 and 8, since this differs significantly from how doNothing()
behaved!
If you got used to this behavior of how the breakpoint on line 4 worked in doNothing()
, you may incorrectly deduce that your code is not executing if you only had a breakpoint on line 5 (or even 4) in this example:
➤ 1
➤ 2 deinit {
➤ 3 number++
4 // incrementNumber()
5 }
6
Note: for breakpoints that pause execution on the same line, they are hit in the order that they were created. To test their order, I set a breakpoint to Log Message and Automatically continue after evaluating actions.
Note: In my testing there was also another potential pitfall that might get you: If you use print("test")
, it will pop up the Debug Area to show you the message (the message appears in bold). However, if you add a breakpoint and tell it to Log Message, it will log it in regular text and not pop open the Debug Area. You have to manually open up the Debug Area to see the output.
Note: This was all tested in Xcode 7.1.1
Deallocation of ViewController
You are misunderstood the deinit
method's job. The deinit is supposed to be called when the instance of a view controller has no reference left to it. So, just simply removing the references of the properties of a view controller doesn't do the whole job.
And you have a misconception of making self.delegate = nil
in your SecondVC
. This should have been done in your first ViewController
.
To make sense of everything, I've done a sample project where you can learn how deinits work. The main code goes here:
First View Controller
class FirstViewController: UIViewController, Navigator {
override func viewDidLoad() {
super.viewDidLoad()
}
deinit {
print("First view controller's deinit called")
}
func passData(data: String) {
print("In First view controller: \(data)")
}
@IBAction func gotoSecond(_ sender: UIButton) {
let viewcontroller = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
viewcontroller.delegate = self
show(viewcontroller, sender: self)
}
}
Second View Controller
protocol Navigator {
func passData(data:String)
}
class SecondViewController: UIViewController {
weak var delegate:Navigator?
override func viewDidLoad() {
super.viewDidLoad()
}
deinit {
print("Second view controller's deinit called")
}
@IBAction func closeButton(_ sender: UIButton) {
delegate?.passData(data: "Delegation from second view controller")
dismiss(animated: true, completion: nil) //when this line executes, the instance of this class is de-referenced. This makes the call to deinit method of this class.
}
}
So, when dismiss
happens for second view controller, the reference count goes to 0
for second view controller and this does the job for calling deinit
method of second view controller.
But you technically don't call the
deinit
of the first view
controller as you don't actually de-reference the first view
controller.
You can find the whole project here.
Dismissing ViewController doesn't deallocate memory in Swift
That Library seems to have an error in the use form, in the example code is declared a method like this
func picker(sender: AZAPicker<PickerItem>, item: PickerItem) {
print("didPickItem: \(item)")
}
but instead of doing that you need to assign a closure in this way and problem solved!
UPDATED (in your code)
self.pickerView!.onPickItem = {[weak self]( sender : AZAPicker<PickerItem>,item:PickerItem) in
print("didPickItem: \(item)")
self.currentPoint = item.number
}
Full Code Reference
class ViewController: UIViewController {
@IBAction func dismiss(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
let config = AZAPickerConfiguration<PickerItem>(items: (1...100).map { PickerItem(number: $0) },
defaultSelectedIndex: 99,
selectionRadiusInPercent: 0.5,
itemWidth: 80)
let pickerView = AZAPicker<PickerItem>(with: config, frame: .zero)
pickerView.backgroundColor = .white
//in this code [weak self] is not needed because I don't use self inside the closure
pickerView.onPickItem = {( sender : AZAPicker<PickerItem>,item:PickerItem) in
print("didPickItem: \(item)")
}
pickerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pickerView)
NSLayoutConstraint(item: pickerView, attribute: .top, relatedBy: .equal, toItem: topLayoutGuide, attribute: .top, multiplier: 1, constant: 20).isActive = true
NSLayoutConstraint(item: pickerView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: pickerView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: pickerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 80).isActive = true
}
}
Why won't this Alert let my view controller deallocate?
Have the YES action handler declare [weak self]
and call self?.popInit()
.
Also, as suggested in a comment, you can replace the NO handler with nil
.
Related Topics
Fblpromises Framework Not Found
How to Set an Environment Object in Preview
Iphonex Not Call Prefersstatusbarhidden
Swift [1,2] Conforms to Anyobject But [Enum.A, Enum.B] Does Not
How to Animate Bordercolor Change in Swift
Controlling Size of Texteditor in Swiftui
How to Avoid That My Swift Async Method Runs on the Main Thread in Swiftui
What Is Trailing Closure Syntax in Swift
Detect Left and Right Click Events on Nsstatusitem (Swift)
Collectionview Not Display Data After Parsing JSON
Swift: Double Conversion Inconsistency. How to Correctly Compare Doubles
Swiftui: How to Make Entire Shape Recognize Gestures When Stroked
How to Make Uitextfield Behave Like a Uisearchbar in Swift
Skaction Completion Handlers; Usage in Swift
Libsqlite3.Dylib and Libz.Dylib Missing in Xcode 7. How to Use Parse