My question is two-part:
First, Say I have a class:
MyClass.h
#interface MyClass: NSObject
-(id)initWithName:(NSString*)name;
#property(nonatomic, strong) NSString *name;
#end
MyClass.m
#implementation MyClass
-(id)initWithName:(NSString*)name
{
if (self = [super init])
{
self.name = name;
}
return self;
}
#end
My question: I know that self will hold the name property strongly. But how will the name property relate to self? What I mean is that I can access name as self.name but while class instantiation, how is the children of self (which in this case is name) related to self? I am imagining the structure of the class as a tree, with the parent holding strong reference to the children and the children holding a weak reference to the parent. I want to know if I am thinking about it correctly or not. My guess is it will be a weak relationship.
Second, if I add a method which has a block that references the name property. So my updated implementation of MyClass.m is:
MyClass.m
#implementation MyClass
-(id)initWithName:(NSString*)name
{
if (self = [super init])
{
self.name = name;
}
return self;
}
-(void)doSomeStuff
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.name = #"Name changed inside block";
}];
}
#end
My second question is: I am not referencing self directly inside my block. So, I guess there is no retain cycle here. But I am referencing name property which is held by self. So does this create a retain cycle?
I know that self will hold the name property strongly. But how
will the name property relate to self?
Each property will have a backing instance variable, conventionally named the same as the property with a leading underscore and a getter and/or setter method. There is no relationship; the property generally makes the class instance larger (due to additional instance variable) and the class larger (due to additional methods).
I am not referencing self directly inside my block. So, I guess there
is no retain cycle here. But I am referencing name property which is
held by self. So does this create a retain cycle?
Yes you are referencing self directly, so a retain cycle is possible. However a retain cycle can only happen under certain circumstances, and it's often just safer to avoid this by creating a weak reference to self and using that within the block.
First: The name property holds no relationship to MyClass, weak or otherwise. (That is, if you pass name to some arbitrary method, it doesn't carry any reference to the MyClass instance where it was a property.)
Second: Since you're simply executing the block rather than storing it, I don't see an opportunity for a retain cycle.
1: The MyClass instance has retained the name property, name property itself has no idea what is MyClass and therefore , there is nothing referring from String-name to the MyClass itself.
2: In the following code
-(void)doSomeStuff
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.name = #"Name changed inside block";
}];
}
self.name = #"Name changed inside block"; is the same as [self setName:#"Name changed inside block"];
So you are actually retaining MyClass instance inside Block and then executing its method to update the name , ( block needs pointer to this Name to change it , right ? block retains class object which contains this property ) , you are not retaining the property name itself.
But how will the name property relate to self? My guess is it will be a weak relationship.
The name property does not have a reference back to self, so the attributes strong and weak don't apply. An object instance is just a collection of instance variables, gathered into a struct. When we talk about object memory management, we are talking about the memory containing that struct. It doesn't make sense to say that a property (really the instance variable backing the property) has a reference to anything. It is simply one part of what self is.
My question: I know that self will hold the name property strongly. But how will the name property relate to self? What I mean is that I can access name as self.name but while class instantiation, how is the children of self (which in this case is name) related to self? I am imagining the structure of the class as a tree, with the parent holding strong reference to the children and the children holding a weak reference to the parent. I want to know if I am thinking about it correctly or not. My guess is it will be a weak relationship.
The children can have a reference to the parent and then it should be weak for the reasons you mentioned. But NSString instances does not have such an up-reference. So there cannot be a retain cycle.
In general it is up to you to manage such inverse relationship. (Core Data does it automatically in its default setters,if you insert a inverse relationship.) Nothing is done automatically, no definition of an up-reference, no setting of a up-reference.
My second question is: I am not referencing self directly inside my block. So, I guess there is no retain cycle here. But I am referencing name property which is held by self. So does this create a retain cycle?
You refer self inside the block, because you use it. Period.
But a retain cycle needs two references. As long as self is used inside the block, but the block is not stored in a property of self (directly or indirectly) no retain cycle can occur.
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
In Swift, we mostly use many references of classes like ,
UITableView
UIStepper
UILabel
NSTimer
UISlider and etc..
one example:
var slider : UISlider!
My question is whether we have to create all these as weak refernces by prefixing it as weak, so that ARC will not have a strong hold on it so ARC can delete it as when needed or just creating a strong reference and make it to nil at the viewDidUnload deligate ??
example :
slider = nil
To the point I actually don't know how to manually use ARC or manually handling ARC is not at all needed ?? I have no idea about this meamory handling
Pls do share if u ever came across this and found a solution...
Thanks in advance....
ARC (Automatic Reference Counting) in Swift is explained pretty well in the official documentation.
Below you can find a very simple recap of 4 important aspects of ARC.
1. Basics
ARC associates to each instance of a Class a retainCount integer.
This value represents the number of strong references to that specific instance.
When this number becomes 0 then the memory used by the instance is freed.
class Something {}
var aVariable = Something()
// now the reference counting for this particular instance of Something is 1
Now our instance of Something is keept in memory since its retainCount value is 1.
var anotherVariable = aVariable
Now we have 2 strong references to our instance of Something. Good! Its retainCount now is 2 and the instance is still kept in memory!
aVariable = nil
The retainCount has just become 1. No problem, the instance is still in memory.
anotherVariable = nil
Finally the retainCount of our instance has become 0. This means that the instance has been freed and can no longer be accessed.
2. Should you set to nil your variables when you're done with them?
Nope. Infact when a variable goes out of scope ARC automatically decrease the retainCount of the referenced instance.
In the following example, before the last } the retainCount of the instance of Something gets decreased and reach value 0 (and is freed).
func doSomethingUseful() {
let something = Something()
// ... do very important stuff here
}
So in a common scenario you don't need to set variables to nil in order to force ARC to free the referenced instance.
Another example:
class Son {}
class Father {
var sons: [Son]
init (sons: [Son]) {
self.sons = sons
}
}
func lifeGoesOn() {
let son = Son()
// here the referenceCout of the instance of Son is 1
let father = Father(sons: [son])
// here the referenceCount of the instance of Son is 2...
// now variable son goes out of scope so the reatinCount of the instance of Son becomes 1
// also father goes out of scope, so the variable father.sons goes out of scope as well, so the `retainCount` of the instance of Son becomes 0
// and so both the instances of Father and Son gets freed
}
You can see this like a domino effect. When an instance is freed, all its references to other instances are removed. So the retainCounts of the referenced instances gets decreased. And if becomes 0 they are released. And so on...
3. Retain cycles
Ok, what happen if I have 2 classes as follow?
class Son {
let father:Father
init(father:Father) {
self.father = father
}
}
class Father {
var sons: [Son]
init (sons: [Son]) {
self.sons = sons
}
}
Lets create now a reference from a father to its son and viceversa from the son to its father.
func lifeGoesOn() {
var father = Father(sons:[])
// retainCount of the instance of Father is 1
var son = Son(father: father)
// retainCount of the instance of Father is 2
// retainCount of the instance of Son is 1
father.sons.append(son)
// retainCount of the instance of Father is 2
// retainCount of the instance of Son is 2
// Now we have a problem
}
At the of the function the father variable goes out of scope so the retainCount of the instance of Father becomes 1.
Similarly the variable son goes out of scope and the retainCount of the instance of Son becomes 1.
The problem here is that the instance of Son references the instance of Father (keeping this instance in alive memory). And the instance of Father references the instane of Son. These 2 instances should not be in memory anymore. They are not accessible by the programmer since all the variable to reference them are gone.
This is a problem.
4. Weak references
When you structure your code you should pay attention to strong retain cycles. Let's how to refactor our code to fix this.
class Son {
weak var father:Father?
init(father:Father) {
self.father = father
}
}
Now the reference from a Son to its Father is weak. This means it does not count when ARC calculates the number of (strong) references to an instance. And this fix the problem seen in the previous paragraph.
I hope the subject is a little bit more clear now. There are several scenarios I did not cover. Again, the official documentation is pretty good and exhaustive.
Update (to better answer the comment below)
If you have a custom UIViewController (lets call it MyCustomViewController) and this class has a strong property to an object let's see what happen.
class MyCustomViewController : UIViewController {
var something = Something()
}
class Something {
init() { // called when memory is allocated
debugPrintln("The instance of Something has been created")
}
deinit { // called when memory is freed
debugPrintln("The instance of Something has been freed")
}
}
When you present a MyCustomViewController, an instance of MyCustomViewController is created. Then an instance of Something is created as well.
Now the instance of MyCustomViewController is referenced by the UINavigationController so has retaintCount = 1.
Similarly the instance of Something is referenced by the instance of MyCustomViewController so it has retainCount = 1.
So the instance of UINavigationController keeps alive the instance of MyCustomViewController. And the instance of MyCustomViewController keeps alive the instance of Something.
UINavigationController -(strong)-> MyCustomViewController -(strong)->
Something
Next you decide to dismiss MyCustomViewController, so iOS animates it to leave the screen. When it is no longer visible it is removed the reference from the instance of UINavigationController to the instance MyCustomViewController.
UINavigationController -(REMOVED)- MyCustomViewController -(strong)->
Something
This means that the retainCount of the instance of MyCustomViewController becomes 0 because: no one is referencing it now!
So the instance of MyCustomViewController is going to be removed from memory. In this process its properties are nulled.
UINavigationController -(REMOVED)- [free memory] -(REMOVED)- Something
Now the retainCount of the instance of Something has become 0.
So it will be removed from memory as well.
UINavigationController -(REMOVED)- [free memory] -(REMOVED)-> [free memory]
Finally, I overidden the init and deinit methods of Something so you can keep track of the allocation and deallocation of a related instance. Looking at the log (or using a breakpoint) you can verify what I said here.
Hope this helps.
If you are talking about view controller properties that are initialised by the view itself (such as UILabel or pretty much any subclass from UIView that you define in IB), Xcode will assign them as weak automatically, as the view (and not the view controller) have created the strong reference.
Most of the times you don't need to manually add weak to your properties, unless you have defined a strong relationship somewhere else in your code (which is the typical case when you have delegates).
ARC mostly just works. You normally do not have to worry about declaring weak when using Cocoa classes such as the ones you listed.
You only have to consider it when you have different classes you've developed yourself that have bi-directional references. (Apartment class and Person class in Apple's example).
I am working on a subclass of SKNode called UtilityNode
#implementation UtilityNode
- (id)initWithName:(NSString *)rootName {
self = [super init];
if(self) {
[self setName:rootName]; // ?
}
return self;
}
#end
I am setting up a designated initialiser for the new node initWithName: where I am trying to initialise the name of the superclass SKNode when creating the new subclass. I was under the impression that I could just write _name = rootName; but _name was flagged as undeclared. I have got it working (as you can see above) by using [self setName:rootName]; Can anyone shine some light on this, am I doing this correctly?
This is correct. The _name instance variable was probably declared as #private (the default for auto-synthesizing properties) and therefore it is inaccessible by subclasses.
In well-designed class hierarchies and specifically framework classes for which there is no source code available you will find most if not all instance variables inaccessible by subclasses because it hides the implementation detail and makes future changes to the base class possible. Imagine if the base class needed to verify the name property whenever it changes - if subclasses could assign directly to the ivar they would bypass the checks added to the ivar setter method.
PS: I find dot notation friendlier on the eyes:
self.name = rootName;
UPDATE regarding the "don't send messages to self in init/dealloc" rule:
This can easily be avoided by redesigning the class to not take non-essential parameters in its init method. A cleaner version of this subclass would be:
UtilityNode* un = [UtilityNode node];
un.name = #"some name";
If the node absolutely requires the parameter to be set, warn the user via an NSAssert in the method where the name is required to be valid.
Is there a mechanism which would allow an object to know that a zeroing weak reference turned nil?
For example I have a property
#property (nonatomic, weak) MyClass *theObject;
when theObject deallocates and the property turns nil I want to get notified. But how? Does the zeroing weak reference system use the setter to set the property to nil when the object goes away?
The runtime just sets the weak ivar _theObect to nil, a custom setter is not called.
What you could do (if you really need the notification):
define a local "watcher" class and implement dealloc in that class,
create a watcher object and set it as "associated object" of _theObject.
When _theObject is deallocated, the associated object is released and deallocated (if there are no other strong refereces to it). Therefore its dealloc method is called. This is your "notification".
(I'm writing this on the phone and can fill in the details later if necessary.)
If you care when an object goes away, you shouldn't be using a weak reference. What are you trying to do?
There is no notification about object deallocation.
The system will not use setter method (this means no KVO notifications will be raised). The ivar is the real weak reference which gets zeroed. The weak keyword on a property is merely an instruction for synthesizing the ivar, and a public declaration that the object is not retained.
Though you can always invent your own notifications and send them from dealloc method of your classes, note that normally you should not ever be interested in such notifications and there is at least one good reason that they don't exist.
Whenever there is any kind of automatic memory management is in use, you can not (by definition) expect objects to die exactly when you need them to, that applies to Objective-C reference counting. Because any component may unexpectedly prolong lifetime of any object for unknown period of time, relying program behavior on assumption that dealloc will be called exactly when you need it to is bad design and a recipe for trouble. dealloc should be used for cleaning up only.
Try this rule of thumb: will the program still work correctly if dealloc does not get called at all? If not, you should rethink program's logic rather than sending out dealloc notifications.
I implemented this using a so-called weak reference registry, see the class BMWeakReferenceRegistry, part of my open source BMCommons framework for iOS.
This class associates context objects with the object of interest. When this object is released, so is the context object and the cleanup block is called.
See the API:
/**
* Registry for monitoring the deallocation of objects of interest to perform cleanup logic once they are released.
*/
#interface BMWeakReferenceRegistry : BMCoreObject
BM_DECLARE_DEFAULT_SINGLETON
/**
* Cleanup block definition
*/
typedef void(^BMWeakReferenceCleanupBlock)(void);
/**
* Registers a reference for monitoring with the supplied cleanup block.
* The cleanup block gets called once the reference object gets deallocated.
*
* It is possible to register the same reference multiple times with different cleanup blocks (even if owner is the same).
* If this is not intended behavior, check hasRegisteredReference:forOwner: before calling this method.
*
* #param reference The object to monitor
* #param owner An optional owner (may be specified to selectively deregister references)
* #param cleanup The cleanup block
*/
- (void)registerReference:(id)reference forOwner:(id)owner withCleanupBlock:(BMWeakReferenceCleanupBlock)cleanup;
/**
* Deregisters the specified reference for monitoring. If owner is not nil, only the monitor(s) for the specified owner is/are removed.
*
* #param reference The monitored reference
* #param owner The optional owner of the reference
*/
- (void)deregisterReference:(id)reference forOwner:(id)owner;
/**
* Checks whether a monitor already exists for the specified reference/owner. If the owner parameter is nil all owners are checked.
*
* #param reference The monitored reference
* #param owner The optional owner
* #return True if registered, false otherwise.
*/
- (BOOL)hasRegisteredReference:(id)reference forOwner:(id)owner;
#end
Based on Martin R's answer, I came up with the following snippet. Just make sure you don't create any retain cycles with your onDeinit closure!
private var key: UInt8 = 0
class WeakWatcher {
private var onDeinit: () -> ()
init(onDeinit: #escaping () -> ()) {
self.onDeinit = onDeinit
}
static func watch(_ obj: Any, onDeinit: #escaping () -> ()) {
watch(obj, key: &key, onDeinit: onDeinit)
}
static func watch(_ obj: Any, key: UnsafeRawPointer, onDeinit: #escaping () -> ()) {
objc_setAssociatedObject(obj, key, WeakWatcher(onDeinit: onDeinit), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
deinit {
self.onDeinit()
}
}
Call it like this when initializing your weak var:
self.weakVar = obj
WeakWatcher.watch(obj, onDeinit: { /* do something */ })
there is no notification system for weak vars.
The following is an example that I used to implement multicast of delegates. It might be useful to illustrate how to monitor the 'dealloc' of weak referenced objects (the delegates).
There will be a master DelegateRef object. Its array keeps record of all delegateRefs which wrap the real delegates. The main purpose here is to remove the strong reference to delegateRefs kept by the array when the real delegates dealloc. Therefore, a local watch object is created and associated to delegate when adding the delegate. When the local watch dealloc, the delegateRef gets removed from the master DelegateRef's array.
#import <objc/runtime.h>
#interface WeakWatcher : NSObject
#property (nonatomic, weak) NSMutableArray *masterarray;
#property (nonatomic, weak) DelegateRef *delegateRef;
#end
#implementation WeakWatcher
-(void)dealloc
{ // when the object dealloc, this will be called
if(_delegateRef != nil)
{
if([self.masterarray containsObject:_delegateRef])
{
[_masterarray removeObject:_delegateRef];
}
}
}
#end
#interface DelegateRef()
#end
#implementation DelegateRef
static char assoKey[] = "assoKey";
- (NSMutableArray *)array {
if (_array == nil) {
_array = [NSMutableArray array];
}
return _array;
}
-(void)addWeakRef:(id)ref
{
if (ref == nil) {
return;
}
DelegateRef *delRef = [DelegateRef new];
WeakWatcher* watcher = [WeakWatcher new]; // create local variable
watcher.delegateRef = delRef;
watcher.masterarray = self.array;
[delRef setDelegateWeakReference:ref];
objc_setAssociatedObject(ref, assoKey, watcher, OBJC_ASSOCIATION_RETAIN);
[self.array addObject:delRef];
}
#end
Apple achieve this on UIPageViewController's weak dataSource property by use of their private _UIWeakHelper class but you can easily implement the same. In the setDataSource setter they create an instance of [_UIWeakHelper.alloc initWithDeallocationBlock:block] and the block calls self.dataSource = nil after the weak/strong dance to avoid a retain cycle. They then call objc_setAssociatedObject on the dataSource object setting the weak helper object. Finally in the _UIWeakHelper dealloc they call the deallocation block. It works because when the dataSource is dealloced the associated _UIWeakHelper will be too.
In case you were wondering why they need this, it is because when the dataSource deallocs they want to disable scrolling of the pages because there are no pages to scroll to.
Just don't make the same mistake Apple have made (as of iOS 13.4.1 Xcode 11.4.1) they associate the helper object to the same key for both the dataSource and the delegate so only one deallocation block is fired, doh!
I've been reading up more on retain cycles all day and I'm starting to confuse myself. So I just wanted to check a couple of things. (Just for clarification, I'm using ARC)
So let's say I have MyFirstClass. MyFirstClass has an strongly pointed (by default) instance variable to MyChildClass:
MyChildClass *_child;
MyFirstClass also has a getter (publicly available in the .h) like so:
-(MyChildClass *)child
{
return _child;
}
Now let's say I have another class entirely, MySecondClass. MySecondClass has a weak instance variable pointing to MyFirstClass like so:
__weak MyFirstClass *_firstClass;
There is a parent class that holds both MyFirstClass and MySecondClass so MySecondClass just has a weak reference to MyFirstClass so it doesn't stop the parent class from releasing it when it wants to.
MySecondClass also has it's own child class, strongly referenced with an instance variable too:
MySecondChildClass *_secondClassChild;
MySecondChildClass wants to reference MyFirstClass's MyChildClass object.
So I guess I use a weak pointer here too, within MySecondChildClass:
__weak MyChildClass *_firstClassChild;
It has a custom init to set this:
-(id)initWithFirstClassChild:(MyChildClass *)firstClassChild
{
if(self = [super init]){
_firstClassChild = firstClassChild;
}
}
Finally, there is a method in MySecondClass that creates MySecondChildClass:
-(void)setupChild
{
_secondClassChild = [[MySecondChildClass alloc] initWithFirstClassChild:_firstClass.child];
}
Is this all correct? I'm 90% sure that's all fine but I'm getting confused.
What about when I'm using _firstClass.child, does that create a strong pointer to it? Should I be referencing __weak somewhere in that method call? How about during MySecondChildClass's init? It has a temporary pointer to MyChildClass before it sets the instance variable, does that create a strong pointer I should worry about?
Any clarification would be great.
I don't think you need any weak references here.
I'm calling these objects P, A, A', B, and B' where:
P is an instance of your "Parent Class"
A is an instance of "MyFirstClass"
A' is an instance of "MyChildClass"
B is an instance of "MySecondClass"
B' is an instance of "MySecondChildClass"
So then your picture looks like this, if I read your question correctly:
/----> A ----> A'
/ ^ ^
P | |
\ | |
\----> B ----> B'
If that picture matches what you wrote, then there is no retain cycle there and you shouldn't therefore need any of those references to be weak.