1

When ARC enabled, following code causes the obj retained twice for the block by calling objc_retain() and objc_retainBlock().(So retainCount becomes 3 after the block definition.)

I checked that obj is not in autorelease pool and there are two objc_release() calls for obj at the end of the method. (I know counting retains does not make sense but i am checking the objc_retain() calls, not barely checking retain counts.) What is the rationale behind this?

-(void)myMethod
{
        NSObject *obj = [[NSObject alloc] init];
        NSLog(@"obj %@ retaincount %ld", obj, CFGetRetainCount((__bridge CFTypeRef)obj));
        void (^myBlock)(void) = ^() 
        {
            NSLog(@"obj %@ retaincount %ld", obj, CFGetRetainCount((__bridge CFTypeRef)obj));            
        };
        NSLog(@"obj %@ retaincount %ld", obj, CFGetRetainCount((__bridge CFTypeRef)obj));    
        myBlock();
}

Isn't it enough to retain the obj just once for capturing it by the block?

Note: Also, when i remove the myBlock variable and the call for it, so just with ^() {...} definition and that definition could never be called, obj is still retained with objc_retain() which seems weird. I am using XCode 4.3.2.

lockedscope
  • 965
  • 17
  • 45
  • Retain counts are deceptive, and the behavior you describe almost certainly depends on your optimization settings. What exactly are you looking for? – Jesse Rusak Dec 16 '13 at 21:58
  • I just want to understand internal rationale. I will not practice with this in any production code. – lockedscope Dec 16 '13 at 22:06
  • 1
    @lockedscope Also remember that this internal implementation may change with each revision of the compiler. Really, there is no reason for you to dwell there. – Léo Natan Dec 16 '13 at 22:09
  • "I know counting retains does not make sense but i am checking the objc_retain() calls, not barely checking retain counts." And what do you think the retain count is, if not just objc_retain() calls? – newacct Dec 16 '13 at 23:36

2 Answers2

13

www.whentouseretaincount.com -- i.e. don't use retainCount as it'll cause nothing but confusion. Even for learning the innards.

If you want to know how and when blocks retain objects, you should look at the compiler, runtime, and blocks runtime sources. All are available.

A block may or may not retain an object. Specifically, a block may only retain an object when the block is copied (as long as the object reference isn't __weak).

Similarly, but orthogonally, ARC's retain/release behavior changes based on the optimization level of the compiler. In particular, DEBUG (-O0) code tends to have lots of retain/release. -Os (optimized) code will have many of these optimized out.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • wouldn't it be nice if Apple would, you know, provide some kind of retain count that beginning devs could use (in some debug mode, in the simulator only, whatever) that actually meant something? I guess that's just silly, whereas "see this thing over here that says clearly that it does what you want? Do not ever, ever use it under any circumstances." – Dan Rosenstark Dec 16 '13 at 23:06
  • 3
    @Yar You'd have to eliminate threading, autorelease pools, and much of ARC's automatic behaviors to make "meaningful" count. At that point, it would be so divorced from reality as to be useless. And that isn't how memory management works in the first place. A "retain" merely means that you want the object to stick around. It says nothing about what else may also want to keep the object alive or how long that might be. – bbum Dec 16 '13 at 23:24
  • You are right bbum. When -Os(optimized) used, objc_retainBlock() is not emitted. – lockedscope Dec 17 '13 at 09:35
3

Please read this: http://whentouseretaincount.com/

You shouldn't use retain count, the apple developers who wrote it advise against it, a lot of smart people advise against it and i'm telling you not to use it.

As for retain cycles its good practice to have a weak property outside of your block scope as such:

__weak typeof(obj) weakObj = obj;
void (^block)(void) = ^{
  [weakObj method];
};
Oliver Atkinson
  • 7,970
  • 32
  • 43
  • Just to note - this is dangerous in the example above, because if he was to return the block, the weak reference would be zeroed at the end of the method. `__weak` should be considered on a case by case. – Léo Natan Dec 16 '13 at 22:08
  • But he doesn't return the block - whats the issue? – Oliver Atkinson Dec 16 '13 at 22:12
  • No issue, just a note. `__weak` should be generally used in blocks when the block-retaining object may be used inside the block. This is not the case. If there was an issue, I would have downvoted. ;) – Léo Natan Dec 16 '13 at 22:13
  • But you are not using weakObj within the block. – lockedscope Dec 16 '13 at 22:14
  • "As for retain cycles its good practice to have a weak property outside of your block scope as such:" I don't see any properties here. Also, this doesn't make sense; why not strong? – newacct Dec 16 '13 at 23:39
  • `__weak typeof(obj) weakObj = obj;` strong can cause retain cycles for reasons mentioned above – Oliver Atkinson Dec 17 '13 at 07:46