Does the absence of a "likely to lead to a retain cycle" warning imply a strong reference cycle will not be created? - objective-c

Per the transitioning to ARC release notes, when referencing self within a block one should use weak references in order to avoid a strong reference/retain cycle:
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
// ...
[strongMyController dismissViewControllerAnimated:YES completion:nil];
// ...
}
else {
// Probably nothing...
}
};
Sometimes, I will get a compiler warning that referencing self in the block is likely to lead to a retain cycle. Does the absence of the warning imply that a retain cycle will not be created? Why is the warning qualified as "likely" to lead to a retain cycle?

Does the absence of the warning imply that a retain cycle will not be created?
No. The compiler is able to determine certain conditions from which you may create a retain cycle but it is impossible for it to rule out the possibility that you may create one. As an example consider the following class:
#interface MyClass : NSObject
#property (readwrite, strong) id myObject;
#end
and the code fragment in a different class:
MyClass *one = [MyClass new];
MyClass *two = [MyClass new];
one.myObject = two;
two.myObject = one; // created a strong cycle...
For a compiler to even spot this simple cycle requires flow analysis across multiple classes, and in general this problem is unsolvable by the compiler (you can scan for/spot the creation of cycles at runtime, ARC does not do this).
Why is the warning qualified as "likely" to lead to a retain cycle?
Creating a cycle itself is not wrong or bad. A cycle is only an issue if it becomes orphaned; i.e. no live references refer to it and it is only the cyclic references which cause the objects in the cycle to remain alive.
When the compiler sees a strong reference to self within a block being created it knows a live strong cycle will be created, but it cannot determine (i.e. unsolvable in general as above) whether that cycle will be later broken before the block is no longer required or whether the creating object and the block will form an orphaned cycle. Hence the use of a non-definitive "likely".

Related

Not expected strange behaviour of ARC during deallocating instances

I'm refreshing my knowledge in Objective-C world and now I'm testing some ARC with __weak local variables.
I have very simple code with such files GAObject.h
#import <Foundation/Foundation.h>
#interface GAObject : NSObject
+ (instancetype)create;
#end
Implementation of this interface GAObject.h
#import "GAObject.h"
#implementation GAObject
+ (instancetype)create {
return [[GAObject alloc] init];
}
- (void)dealloc {
NSLog(#"GAObject is being deallocated");
}
#end
So there is simple factory method create and I override dealloc method to watch if objects was deallocated when I expecting this. Now the funny part main.m:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Learning/GAObject.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
NSLog(#"1");
NSObject *o1 = [[GAObject alloc] init];
NSObject * __weak weakObject = o1; // Line 1
o1 = nil; // o1 should be deallocated because there is no strong references pointing to o1.
NSLog(#"2");
NSObject *o2 = [GAObject create]; // Line 2
o2 = nil; // o2 should be deallocated here too but it is not deallocated. Why?
NSLog(#"3");
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
In the output I see this:
1
GAObject is being deallocated
2
3
But My expecting results should be:
1
GAObject is being deallocated
2
GAObject is being deallocated
3
If I create o2 using factory method then I have this behaviour. If I create o2 like this: [[GAObject alloc] init] then I get expected output. Also I noticed that when I remove line with weakObject I also get expected results. Can somebody explain it?
It's because ARC still respects the Cocoa memory-management naming conventions.
Under those conventions, a method named +create returns a +0 reference. So, in the implementation of the method, ARC has to balance the +1 reference of the alloc/init pair by autoreleasing the reference.
Then, in main(), ARC has to assume it has received a +0 reference from the call to +create. If it needed the reference to survive the current scope, it would retain it, but it doesn't so it doesn't. The second GAObject instance would be deallocated when the autorelease pool is drained, but that will never happen because UIApplicationMain() never returns. If you use two separate autorelease pools, one for the code dealing with GAObjects and another for the call to UIApplicationMain(), I expect you'll get the result you expect.
If ARC did need the reference to survive, it would retain at the assignment to the strong variable and release when that variable is assigned a new value (including nil) or goes out of scope. ARC has a run-time optimization that an autorelease-return in a callee and a retain of the returned value in the caller cancel each other out, such that the object is never put in the autorelease pool. If this were happening, you would get your expected results.
In fact, my expectation is that the compiler initially would emit that retain and release even in your case, but a subsequent pass removes redundant retains and releases. Your example has the release immediately follow the retain, which makes it even more obvious to the compiler that the pair are redundant. Because the retain gets removed, that autorelease optimization doesn't kick in, and a reference to your object really does get put into the autorelease pool.
If your method were named +newGAObject, then the naming conventions would mean it returns a +1 reference and this all changes. (Of course, as it stands, your +create method is just doing the same thing as the built-in +new method, except for the autorelease that ARC has to add. So, you could just change the calling code to use +new and that would also sidestep this issue.)
I don't know why the line with weakObject matters. But, since the behavior you're seeing depends on certain optimizations, anything that could tweak the optimizations can change the outcome.

Circular references in Objective-C and clang

Why doesn't the static analyser detect circular references with blocks? I remember it used to do it when I had retains on my delegates instead of assign, pre-blocks introduction. I remember the nice little lines it used to draw on my code (i think...)
If I do this, without using weakSelf, I know I'm going to get a circular reference.
// Note 1: myObject is 'retained' by self.
// Note 2: myObject retains the block for the future
[self.myObject registerBlockOfCodeForFutureExectution:^{
[self doSomething];
}];
Sample Project Exploiting Issue
Now if I know this, and I'm a stupid human, then why doesn't my intelligent computer know this is bad and warn me that I'm being stupid?
There must be a logical reason why it can't detect it, and I want to know what that reason is.
This question is regarding clang and static analysis, please don't suggest how I fix circular references - I know how to do this.
If you use self inside of block it does not automatically mean that you get retain cycle. You get retain cycle only if life-time of block depends on life-time of self object. That may be the case if self has strong reference to myObject or some more complex dependencies are also possible (I assume that it indeed 'saves' block passed to a method, so you already have strong reference there).
So to have retain cycle in your example you need to have two following conditions met (neither of them follows from the code you posted), and compiler needs to be aware of them:
1. Life-time of myObject is tied to self - lets assume that self has strong reference to it
2. saveThisBlockInMyObject: retains block passed to it
I made a small sample that gives compiler warning about capturing self - to address 1st point I declared myObject as a strong property of some class:
#property (strong) MyTestClass* myObj;
...
self.myObj = [MyTestClass new];
For 2nd point I could not find a way to specify that method retains its argument (there're source annotations for returned values, but there's no relevant annotations for method parameters). But you declare block as a strong property of your test class, then compiler is happy to warn you about possible retain cycle:
typedef void (^MyVoidBlock)();
// MyTestClass
#property (nonatomic, copy) MyVoidBlock voidBlock;
self.voidBlock = ^{
[self doSomething]; // Warning!
};
Hope that makes sense :)
The code posted to github does cause a retain cycle.
Current github code:
#interface MyObject ()
#property (nonatomic, copy) dispatch_block_t codeToRunInFuture;
#end
#implementation MyObject
- (void) registerBlockForFuture:(dispatch_block_t)block {
self.codeToRunInFuture = block;
}
// Call in ViewController
self.myObject = [MyObject.alloc init];
[self.myObject registerBlockForFuture:^{
[self runThisInFuture];
}];
I can see where this would be difficult to catch since the Analyzer can not know what block might be and therefore can not tell if there is a self reference either strong or weak. It would have to examine all instances where registerBlockForFuture: is called and the block in each case.
The answer might be to submit a bugreport to Apple.

How can a weakly retained block cause a retain cycle when capturing "self"

I have a class with a property which is a weak reference to a block.
#interface BlockTest : NSObject
#property (nonatomic, weak) void(^testBlock)();
#end
At another point in the class I use this block like this:
- (void)foobar {
self.testBlock = ^{
[self doSomething];
};
}
The compiler (Apple LLVM 3.0) complains that there might be a retain cycle because self is strongly captured here. But I fail to see how this leads to a retain cycle because the block itself is a __weakreference, so it should be fine. If I understood ARC weak references correctly, when the -foobar method returns the block passed to self.testBlock should be deallocated (if not held elsewhere) and thus also release self.
What's the reason the compiler still thinks there might be a retain cycle?
Blocks strongly capture objects within them regardless of how the block itself is referenced. The retain cycle warning is just that, a warning of the possibility. If you know based on the context of your app that this use will not cause a retain cycle you can safely ignore it. To get rid of the warning, you can pass self through an intermediary, strong or weak, as follows:
__weak typeof(self) weakSelf = self;
self.testBlock = ^{
[weakSelf doSomething];
};
I'd change your block property to be a strong reference and do the above.

Use autorelease when setting a retain property using dot syntax?

I see in some sample code that autorelease is used. I am not familiar with the instances when this is required. For example, if I create an annotation object
Header file
#interface someViewController: UIViewController
{
Annotation *annotation;
}
#property (nonatomic, retain) Annotation *annotation;
#end
Implementation file
#implementation someViewController
#synthesize annotation
#end
Question: Is it the correct approach if I initialize my annotation object in the implementation file like this?
self.annotation = [[Annotation alloc] initWithCoordinate:location];
Do I need to set autorelease for this? Or can I just do it the normal way and add the release in the dealloc method?
this is correct:
self.annotation = [[[Annotation alloc] initWithCoordinate:location] autorelease];
because annotation property is declared as a retain property, so assigning to it will increment its retain count.
you will also need, all the same, to release self.annotation in -dealloc.
in short:
init will set retain count to 1;
assigning to self.annotation, will set it to 2;
autorelease will set it back to 1 when the main loop is executed again;
release in dealloc will set the retain count to 0, so that the object will be deallocated);
the best way to think of autorelease is the following, in my opinion: autorelease will "schedule" an "automatic" release for your object at some (near) point in future (typically when the control flow goes back to the main loop, but details are hidden in the hands of Apple).
autorelease is mostly useful in conjunction with init, specifically in the following cases:
when you init a local variable, so that you don't have to release it explicitly before it goes out of scope (the main loop will do that for you);
when you return a pointer to an object you have just created without keeping ownership of it (typical case of the create/make* kind of selectors, the receiver is required to retain it to get ownership);
with properties that retain, when you assign to them an object that they should own uniquely;
with data structures that increment the retain count (NSMutableArray, NSMutableDictionary, etc): you should generally autorelease a newly inited object when you add it to such data structure.
apart from case 2, it is evident that the use of autorelease is meant to improve readability of the code and reduce the potential for errors (meaning that in all of the other cases, you could simply release explicitly your object after the assignment or at the end of the scope).
when using properties, you have always to check whether they are of the retain or assign/copy case; in the first case, assigning a newly inited object to a property generally requires autorelease.
Anyway, I would suggest at least skimming one of the many tutorial on memory management for iOS.
Autorelease is telling the object to release itself before leaving the scope.
Sometimes when you code, you'll encounter something like this
- (void)doSomething
{
if(true)
{
NSString *foo = [[NSString alloc] initWithString:#"foo"];
//Some execution here
[foo release];
}
}
- (void)doSomething
{
if(true)
{
//By doing this is telling to to release foo object before getting out of the scope
//which is similar with above practice
NSString *foo = [[[NSString alloc] initWithString:#"foo"] autorelease];
//Or you can do it this way
NSString *foo = [[NSString alloc] initWithString:#"foo"];
[foo autorelease];
//Some execution carry on, it'll release foo before entering next scope
}
//This is out of the scope
}
Of course, releasing an object doesn't mean deallocating the object.
Sometimes you retain the object so you can still use it outside of its scope.
Judging from your question, if your the object is located within your header file/interface.
You should release it in dealloc method. CMIIW.

I have a circular reference. How can I create a weak reference in Objective-C?

I'm working on an iPhone application. I have an object of class Row that needs to release numerous objects of the class Block. Every Block currently has a property that retains an instance variable of class Row.
#interface Block : UIImageView {
Row *yCoord;
}
#property (nonatomic,retain) Row *yCoord;
#end
Every Row contains an NSMutableArray of these Blocks.
#interface Row : NSObject {
NSMutableArray *blocks;
}
-(void)addBlock:(Block*)aBlock;
#end
#implementation Row
-(void)addBlock:(Block*)aBlock {
[blocks addObject:aBlock];
aBlock.yCoord = self;
}
#end
I understand that this is a circular reference. Apple's documentation states that in order to deallocate an object with a circular reference I need a weak reference instead of a strong reference (a retain property), but it doesn't follow through and explain how exactly I go about doing so. I plan to release and dealloc all Blocks within a Row as well as the Row itself simultaneously. How do I set up a weak reference within each of my Blocks to their "parent" Row?
Edit: Since the asker clarified he's not using garbage collection (iPhone currently does not support it), my advice is to avoid cycles by having only one of the objects retain the other, just as you would do with a delegate. When using properties, use "assign" instead of "retain" to achieve this. For example:
#property (nonatomic,assign) Row *yCoord;
The rest of my answer answer relates to "weak references" in terms of Objective-C 2.0 and GC.
When you're working with garbage collection (10.5+), a weak reference is created by prefixing a variable declaration with __weak. When you assign to that variable, the GC (if enabled) keeps track of the reference and will zero it out for you automatically if all strong references to the referenced object disappear. (If GC is not enabled, the __weak attribute is ignored.)
Thus, you can safely modify the above answer to play nicer with garbage collection (currently on 10.5+, and perhaps someday on iPhone) as follows: (See the related Apple docs.)
#property (nonatomic,assign) __weak Row *yCoord;
To quote Chris Hanson (where you can find more detailed information):
"By prefixing an instance variable declaration with __weak, you tell the garbage collector that if it's the only reference to an object that the object should be considered collectable."
I'd clarify that by saying "if there are no non-weak references to an object". As soon as the last strong reference is removed, the object may be collected, and all weak references will be zeroed automatically.
Note: This isn't directly related to creating weak references, but there is also a __strong attribute, but since Objective-C object variables are strong references by default, it is generally used only for raw C pointers to things like structs or primitives that the Garbage Collector will not treat as roots, and will be collected from under you if you don't declare them as strong. (Whereas the lack of __weak can cause retain cycles and memory leaks, the lack of __strong can result in memory stomping and really strange and insidious bugs that occur non-deterministically and can be quite difficult to track down.)
Just change it to assign instead of retain, no more circular references.
#interface Block : UIImageView {
Row *yCoord;
}
#property (nonatomic,assign) Row *yCoord;
#end
A weak reference is simply an assignment (unless you're talking about Garbage Collection which is a whole separate can of worms, but does not suffer from retain cycles).
Normally, in Cocoa, Row would retain the Block objects (by including them in the NSMutableArray), but Block would not retain Row, each would simply store it in an ivar (with an "assign" property).
As long as Row is careful to release each Block before it is deallocated (ie, its dealloc should release the NSMutableArray which will release the Blocks as long as no one else has any pointers to them) then everything will be deallocated as appropriate.
You can also take the precaution of zeroing the row reference from Blocks before removing the entiries from the array, something like:
- (void) dealloc {
for (Block* b in _blocks) {
b.row = nil;
}
[_blocks release];
[super dealloc];
}
where _blocks is the ivar referenced by the blocks property.
Using assign to create weak references can be unsafe in a multithreaded system, particularly when either object can be retained by a third object, and then used to dereference the other object.
Fortunately, this is often a problem of hierarchy, and the object containing the weak reference only cares about the object it refers to for the referred-to object's lifetime. This is the usual situation with a Superior<->Subordinate relationship.
I think that the case in the OP's comment maps to this, with Row = Superior, Block = Subordinate.
In this case, I would use a handle to refer to the Superior from the Subordinate:
// Superior.h
#class Superior;
#interface SuperiorHandle : NSObject {
#private
Superior* superior_;
}
// note the deliberate avoidance of "nonatomic"
#property (readonly) Superior *superior;
#end
#interface Superior : NSObject {
#private
SuperiorHandle *handle_;
// add one or more references to Subordinate instances
}
// note the deliberate avoidance of "nonatomic"
#property (readonly) SuperiorHandle *handle;
#end
// Superior.m
#import "Superior.h"
#implementation SuperiorHandle
#synthesize
superior = superior_;
- (id)initWithSuperior:(Superior *)superior {
if ((self = [super init])) {
superior_ = superior; // weak reference
}
}
- (void)invalidate {
#synchronized (self) {
superior_ = nil;
}
}
- (Superior *)superior {
#synchronized (self) {
// retain and autorelease is required to prevent dealloc before we're ready, thanks to AndroidDev for pointing out this mistake
return [[superior_ retain] autorelease];
}
}
#end
#implementation Superior
#synthesize
handle = handle_;
- (id)init {
if ((self = [super init])) {
handle_ = [[SuperiorHandle alloc] initWithSuperior:self];
}
return self;
}
- (void)dealloc {
[handle_ invalidate];
[handle_ release];
[super dealloc];
}
#end
// Subordinate.h
#class Superior;
#class SuperiorHandle;
#interface Subordinate : NSObject {
#private
SuperiorHandle *superior_handle_;
}
#property (readonly) Superior *superior;
#end
// Subordinate.m
#import "Subordinate.h"
#import "Superior.h"
#implementation Subordinate
// no synthesize this time, superior's implementation is special
- (id)initWithSuperior:(Superior *)superior {
if ((self = [super init])) {
superior_handle_ = [superior.handle retain];
}
return self;
}
- (void)dealloc {
[superior_handle_ release];
[super dealloc];
}
- (Superior *)superior {
#synchronized (superior_handle_) {
return superior_handle_.superior;
}
}
#end
Some advantages:
It's thread safe. There is no way you can have the weak reference contained in Subordinate become an invalid pointer. It may become nil but that is OK.
Only the objects themselves need to know about the embedded weak reference. All other objects can treat Subordinate as if it has a regular reference to Superior.