2

我在“块编程主题”中读过这个

“块的每次调用都会提供该变量的新副本。这些变量又可以用作包含在块中的块中的常量或引用变量。”

所以,我测试了以下代码。

// 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;
}

我预计执行 blockTest 时“John”保留计数将为 2,但结果为 1。

谁能帮我理解它?

4

3 回答 3

1

您的报价不完整。如果您阅读之前的内容:

在块的词法范围内声明的局部变量,其行为与函数中的局部变量完全相同。

您会看到更准确的报价是:

块的每次调用都提供了[局部变量]的新副本。这些变量又可以用作包含在块中的块中的常量或引用变量。

john不是块本地的,所以引用不适用;它适用于块中定义的变量。此外,“提供一个新副本”并不意味着copy消息被发送到变量contents,它意味着有一个单独的变量具有相同的名称,就像每个函数调用都会产生一个局部变量的新副本(“行为完全一样就像函数中的局部变量一样”)。

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;
}

输出:

添加2(0):2
添加3(0):3
于 2012-07-19T01:29:42.223 回答
0

来自Apple关于retainCount:

重要此方法在调试内存管理问题时通常没有价值。因为任何数量的框架对象可能已经保留了一个对象以保存对它的引用,而同时自动释放池可能在一个对象上保存了任何数量的延迟释放,所以您不太可能从中获得有用的信息方法。

于 2012-07-19T01:23:27.527 回答
0

注意:假设此答案禁用了 ARC,就像在 ARC 环境中一样,这将完全改变。

当一个块捕获一个变量时,它会将指针 const 复制到您正在使用的对象,而不是对象本身。

例子:

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];
}

因此,当您调用 时-retainCount,它相当于外部变量的 retainCount,因为没有调用可以增加接收者的 retainCount 的方法。

于 2012-07-19T01:23:49.310 回答