2

I have read this in "Block Programming Topics"

"Each invocation of the block provides a new copy of that variable. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block."

So, I have tested following code.

// Employee.h
@interface Employee : NSObject
@end

// Employee.m
@implement Employee
@end

// main.m
int main() {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    Employee* john = [[Employee alloc] init] autorelease];

    void (^blockTest)(void) = ^ {
        NSLog(@"john = %@", john);
        NSLog(@"john retain count = %ld", [john retainCount]);
    };

    blockTest();

    [pool drain];
    return 0;
}

I have expected "John" retain count will be 2 when blockTest is executed, but result is 1.

Can anyone help me to understand it?

Daoxin
  • 41
  • 1
  • 2
  • 2
    http://whentouseretaincount.com – Richard J. Ross III Jul 19 '12 at 01:20
  • Variable "John" is not copied into blockTest when it executes? – Daoxin Jul 19 '12 at 01:24
  • @Daoxin: which variable is "that variable"? Taking quotes out of context can change their meaning or add ambiguity. Examining what "that variable" is will likely resolve your confusion. – outis Jul 19 '12 at 01:27
  • @Daoxin: no, "that variable" is "local to the block". `john` isn't local to the block, which is the source of your confusion: the quote doesn't apply to your sample code. – outis Jul 19 '12 at 01:42

3 Answers3

1

Your quote is incomplete. If you read what comes before it:

Local variables declared within the lexical scope of the block, which behave exactly like local variables in a function.

you'll see that a more accurate quote is:

Each invocation of the block provides a new copy of [local variables]. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block.

john isn't local to the block, so the quote doesn't apply; it applies to variables defined in the block. Also, "provides a new copy" doesn't mean the copy message is sent to the variable contents, it means that there's a separate variable that has the same name, just as every function call produces a new copy of local variables ("behave exactly like local variables in a function").

typedef int (^IntFunc)(int);
typedef IntFunc (^IntFuncFunc)(int);

int main() {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    IntFuncFunc makeAdder;
    IntFunc add2, add3;

    makeAdder = ^(int x) {
        // 'x' is local to this block. Each invocation provides a new copy of 'x'
        return (IntFunc) [[^(int y) {
            return x + y;
        } copy] autorelease];
    };
    add2 = makeAdder(2);
    add3 = makeAdder(3);
    // add2 and add3 each refer to an 'x', but it's not a shared 'x'        
    NSLog(@"add2(0): %d\nadd3(0): %d\n", add2(0), add3(0));

    [pool drain];
    return 0;
}

Output:

add2(0): 2
add3(0): 3
outis
  • 68,704
  • 19
  • 132
  • 197
  • Sorry, my quote is just to copy from Apple's document. – Daoxin Jul 19 '12 at 01:33
  • Here is full one."Local variables declared within the lexical scope of the block, which behave exactly like local variables in a function. Each invocation of the block provides a new copy of that variable. These variables can in turn be used as const or by-reference variables in blocks enclosed within the block." – Daoxin Jul 19 '12 at 01:41
0

From Apple regarding retainCount:

Important This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.

Erik
  • 6,796
  • 7
  • 54
  • 97
  • Why I use retainCount is just check to "John" is retained or not. – Daoxin Jul 19 '12 at 01:28
  • But that's the issue -- checking retainCount doesn't really tell you. See also: http://stackoverflow.com/questions/4636146/when-to-use-retaincount – Erik Jul 19 '12 at 01:30
  • I have overwrite copy and retain of Employee class, but neither called. – Daoxin Jul 19 '12 at 01:32
  • >Erik: all AppKit or Foundation class's retainCount doesn't behave same. (i.g. NSString, NSNumber's retainCount won't help us anything). But if you made class just derived from NSObject, you will know retainCount works correctly. – Daoxin Jul 19 '12 at 01:37
0

Note: assuming that ARC is disabled for this answer, as in an ARC environment, this changes completely.

When a block captures a variable, it const-copies the pointer to the object that you are using, but not the object itself.

Example:

void copyPointer(NSObject *input)
{
    NSLog(@"I have copied the input's pointer! %@", input);
}

void copyObject(NSObject *input)
{
    input = [input copy];

    NSLog(@"I have copied the object itself! %@", input);

    [input release];
}

Thus, when you call -retainCount, it is equivalent to the retainCount of the outer variable, since there is no methods that are called that could increase the retainCount of the receiver.

Richard J. Ross III
  • 53,315
  • 24
  • 127
  • 192