I have some code in a UIViewController that isn't being deallocated, which I don't know whether or not is causing the issue. I can't easily comment it out because it's used in a lot of places. Would this code create a strong reference cycle?
class something {
var A = B()
var C {
get {
return self.A.D
}
}
}
Does property C cause a retain cycle?
Related
My sample code like this (just a sample):
[self.view touchActionWithCompeletion:^(NSSting *text){
self.label.text = text;
}];
The block is a parameter of a method, the method is a instance method of self.view, then I access self in block. If self.view is a strong property, will this situation create retain cycle? And will self.view strong reference the block?
Adding my comment above as answer, after testing the code myself to confirm the logic I mentioned,
I think it should not, dead lock ( I mean memory leak, two strongly held objects holding the reference to each other and never being de-allocated hence I mentioned deadlock) will happen only if you pass a strong reference of an object to the block (in this case self) and then the passed object holds a strong reference to block itself (directly or indirectly).
Hoping that method touchActionWithCompeletion will not save the block passed to it with a strong reference this should not result in a retain cycle
EDIT:
Tested your code and deinit gets called as expected.
Here is what I tried,
class MyView : UIView {
func touchActionWithCompeletion(block :(NSString)->()) {
block("abcd");
}
}
class ThirdViewController: UIViewController {
var myViewInstance = MyView()
#IBOutlet var c: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.myViewInstance.touchActionWithCompeletion { (abcd) in
self.c.text = abcd as String
}
}
deinit {
print("deinit called")
}
}
As expected deinit called.
Only thing to notice here, method touchActionWithCompeletion will not store the block passed to it with strong reference. It simply executes it. So my answer above holds true in this case.
EDIT 2:(Clarifying my statement in answer)
I happened mention the passed object holds a strong reference to block itself (directly or indirectly) I guess I need to explain why I mentioned indirectly.
Consider this case, Deadlock will happen if View holds a strong reference to the block passed to its method. Though the strong object passed here to the block is self and self does not hold the reference to block directly, it still result in deadlock if View holds a strong reference to block.
Reason Self - holds a strong reference -> View - holds a strong reference -> Block - holds a strong reference -> Self
Hence deadlock. Though self does not hold the block directly, because it holds the block indirectly, hence deinit on self will not be called. Hence I happened to mention the passed object holds a strong reference to block itself (directly or indirectly)
Hope it helps
I am new to ios development and i want to learn how memory leak will occur in swift or in Objective-C, can any one explain with small example?
Thanks
Small example:
class A {
var b: B!
deinit {
print("deinit of A")
}
}
class B {
var a: A!
deinit {
print("deinit of B")
}
}
do {
let a = A()
let b = B()
a.b = b
b.a = a
}
If you run this code (maybe in Playground), it will print nothing. It means that deinit never called for both objects and they just leaked.
But if you declare one of the properties as weak:
class A {
weak var b: B!
deinit {
print("deinit of A")
}
}
Then deinit will be called and you'll see messages in console.
Edit: add example with closures
Consider this example:
class C {
var f: (Void -> Void)!
deinit {
print("deinit for C")
}
}
do {
let c = C()
c.f = {
print(c)
}
}
c captures f, f captures c. So we got memory leak.
To deal with leaks in closures, you have 2 options – declare that captured object is weak or unowned. Like this:
do {
let c = C()
c.f = { [weak c] in
print(c)
}
}
Basically, you would use weak if it's possible for object to get out of existence and become nil when closure is called; but if you are sure object will still exist at this time, use unowned instead.
After I declare c as weak inside a closure, "deinit for C" is printed – means that everything deallocated successfully.
What this all means for you, the developer?
Almost all the time you don't have to worry about the memory management. It's done for you, automatically. Objects just exist when you need them and vanish when you don't. But there are 2 very common cases when you need to be careful and think about memory.
Delegation. It's common pattern in Cocoa and it could create retain cycles if done wrong. Always declare your delegate as weak unless you have a good reason not to.
Closures. Closure capture references for objects in surrounding scope and does it automatically, without notice. When implementing closure, chech if it will create retain cycle. If yes, declare problem variables as weak or unowned.
For further info I suggest you read official Apple Swift book which can be found in iBooks or here as a website.
I've been reading a bunch about Swift initilization lately, and one solution that appears to have some merit is utilizing lazy variables to avoid the doom and gloom of optionals, especially when extending UIViewControllers or other classes along those lines. With that in mind, I've got code that looks like this:
final class MyViewController : UIViewController {
lazy private var myOtherViewController: MyOtherViewController = MyOtherViewController()
deinit {
// myOtherViewController = nil // Can't do this. Expression resolves to an unused l-value
}
override func viewDidLoad() {
super.viewDidLoad()
myOtherViewController.foo();
}
}
// elsewhere...
final class MyOtherViewController : UIViewController {
deinit {
print("Deinit!")
}
}
In the example here it appears that MyOtherViewController's deinit method never seems to fire, but I also have no way to make myOtherViewController deinit. Setting it to nil isn't allowed. Is there something I'm missing that forces MyOtherViewController to retain? Or have I just been impatient with the garbage collector?
To do this, your lazy variable would have to be declared as optional even though you intend to initialize it as soon as the value is needed (i.e. lazily).
class MyObject {
func run() {
print( "MyObject :: run()" )
}
init() {
print( "MyObject :: init" )
}
deinit {
print( "MyObject :: deinit" )
}
}
class MyContext {
lazy var myObject:MyObject? = MyObject()
}
let myContext = MyContext()
myContext.myObject?.run() //< "MyObject :: init"
myContext.myObject = nil //< "MyObject :: deinit"
Also, I disagree with the notion of the "doom and gloom of optionals"—one only need know which of the many available techniques is most convenient and practical way handle them, and how to avoid allowing too many permutations of state to exist among combinations of optional and non-optional values in a given context. Furthermore, an optional is actually exactly what you want here because you intend to nullify it. Employing an optional doesn't mean that a value will be nil for now until you initialize it, but rather that it may be nil at any point in its life, even if it is defined at declaration or any other time beforehand. If avoiding optionals is truly that high of a priority for you, you'd have to take a step back and re-evaluate your architecture to create a situation where you no longer have the need to de-initialize the value.
I agree with Grimxn, that this pattern of setting that property to nil (and thus needing to make it optional in order to be able to do that) is unnecessary. When MyViewController is deallocated, it automatically releases its strong reference to MyOtherViewController.
The only time you need to manually nil this property is when you have to resolve a strong reference cycle (and if you had such cycle, you can't resolve that in deinit, but rather viewDidDisappear or something like that).
If you're not seeing this other view controller get deallocated, then I'd suggest finding the source of the strong reference cycle and resolving that.
I've recently started profiling one of my iOS app written in swift and realized how annoying ARC is compared to other more adopted GC like Mark-And-Sweep.
One of the most prevalent causes for Strong Reference Cycle was retaining instance property within a closure that is passed to another object retained, again, by the class.
For example,
class MyClass {
private let text = "hello world"
private let anotherClass = AnotherClass()
init() {
addText()
}
private func addText() {
anotherClass.addText { return self.text }
}
}
Retain cycle like above can be avoided by passing argument to the method instead of accessing self directly.
class MyClass {
private let text = "hello world"
private let anotherClass = AnotherClass()
init() {
addText(text)
}
private func addText(text:String) {
anotherClass.addText { return text }
}
}
Is the second approach considered a good practice?
FYI, I'm aware that retain cycle like above can be broken using capture list. I'm just curious as to patterns that are more resilient to memory leaks.
Since the property let text ... is a constant, I think that the second approach is fine and can be considered a best practice.
But if you use the same approach with a var text ... property, then the behaviour changes:
in the first approach an execution of the closure will use the current value of text,
while in the second approach an execution of the closure will always use the original value of text.
I was playing with unowned references. As I understood from the WWDC videos, unowned references can't be nil, and they do not increase the retain count of whatever object they reference. I thought that if an unowned reference is deallocated, then the object that held the unowned reference is also deallocated.
Consider the following code:
class Parent {
var child : Child?
func foo() {
println("Hello")
}
}
class Child {
unowned let parent : Parent
init(parent: Parent) {
self.parent = parent
}
}
var parent : Parent? = Parent()
parent!.child = Child(parent: parent!)
weak var child = parent!.child
parent = nil
child!.parent.foo()
This code works! How come child exists, and moreover, how come parent apparently still exists? I had thought that after setting parent = nil, child would also be nil. It seems as if the unowned reference is acting as if it were a strong reference.
Any ideas as to why this code works?
Your code will most likely only work in the playground, where the memory management is a little... fuzzy.
When I ran this in Xcode, it crashes as you'd expect. The playground is meant to make it easy to test the syntax, play with some classes, etc. It's not the best place to play around with weak/unretained variables.
I haven't found any documented sources describing how exactly the memory is managed in a playground, but it's definitely different from how it will be in an actual runtime.