有人可以告诉我为什么localComplete块和self.block的内存地址是一样的吗? self.complete的属性设置为copy,并且为了确保我在将localComplete分配给self.complete时也在localComplete上调用copy。
- (void) test {
CompletionBlock localComplete = ^{
};
NSLog(@"localComplete - %p", localComplete);
self.block = [localComplete copy];
NSLog(@"self.complete - %p", self.block);
self.block();
}
这是输出:
2013-10-05 08:39:18.549 TestApp[90703:a0b] localComplete - 0x60b8
2013-10-05 08:39:18.550 TestApp[90703:a0b] self.complete - 0x60b8
作为另一个例子,我创建了字符串:
// creating string
self.carType = [[NSString alloc] initWithFormat: @"Good%@", @"year"];
NSLog(@"self.carType - %p", self.carType);
// same memory address???
NSString *carInitString = [[NSString alloc] initWithString: self.carType];
NSLog(@"carInitString - %p", carInitString);
// same memory address???
NSString *carCopy = [self.carType copy];
NSLog(@"carCopy - %p", carCopy);
// different memory address
NSString *carInitWithFormat = [[NSString alloc] initWithFormat: @"%@", self.carType];
NSLog(@"carInitWithFormat - %p", carInitWithFormat);
输出:
2013-10-05 09:45:01.667 TestApp[91103:a0b] self.carType - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitString - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carCopy - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitWithFormat - 0xa336b70
为什么carInitString和carCopy的内存地址不同?在项目构建设置中关闭了优化。
答案 0 :(得分:3)
关于您的原始问题,通常在堆栈上分配块。复制块(使用Block_Copy
函数或-copy
方法)将移动块上的块(进一步调用只会增加块的保留计数)
Block_copy [...],给定一个块指针,将底层块对象复制到堆中,将其引用计数设置为1并返回新块指针,或者(如果块对象已经在堆上)将参考计数增加1
(source)
所以在你的例子中,你可能期望不同的地址,因为第一个块是本地的,而第二个块在堆上, BUT ,因为那个特定的块没有做任何引用对于周围的范围,编译器会将其标记为全局块。全局块不在堆栈上分配,而是在内存中的固定位置。
复制全局块不会将块移动到任何位置。它只会增加其保留计数,因为该对象已经在堆上。这就是为什么你没有得到两个不同的地址。
尝试使用对周围上下文的引用来创建一个块,并且您将拥有两个不同的地址(堆栈和堆)。
现在,让我们解答有关NSString
的问题。
复制不可变对象可能导致retain
作为优化(我的意思是,框架设计优化,编译器与它无关),具体取决于类如何实现NSCopying
协议
对于许多基础课程,例如NSString
,NSArray
,NSSet
...
这完全符合NSCopying
协议规范,您可以在documentation中阅读:
您实施此协议的选项如下:
...
- 当类及其内容不可变时,保留原始文件而不是创建新副本来实现NSCopying。
正如Greg Parker在评论中所指出的,-[NSString initWithString:]
执行相同类型的优化。如果将不可变字符串作为参数传递,它只会保留并返回相同的字符串。
在一些情况下这是一种有用的行为,这里有一个例子:你声明一个属性
@property (nonatomic, copy) NSArray *anArray;
然后在界面中公开它。
将其声明为copy
是一种很好的做法,以确保您以后正在处理的对象不会被客户端更改。如果您只是保留它并且客户端传入NSMutableArray
,则无法阻止她操纵该对象。
所以复制很好,但看起来它有价格:即使你不需要(即它是不可变的),你也会复制该对象。
由于上面讨论的行为,您不会支付这样的费用。将copy
发送到NSArray
只会保留它,而将其发送到NSMutableArray
实际上会复制它,所以在这种情况下是一个很大的胜利。
答案 1 :(得分:1)
可能是因为副本不是必需的。你没有捕获任何变量或类似的东西。所以块也许是不变的。尝试让它引用本地或__block变量。