我熟悉__block
语句,它使变量'可赋值'在一个Block中。
但是我发现当使用一些使用块作为方法中的参数的Objective-C特性时,一些变量是可分配的,即使它们没有用这个__block
语句声明。
以下是2个代码:
[UIView animateWithDuration:2 animations:^
{
self.animatedView.backgroundColor = [UIColor blueColor];
self.animatedView.center = CGPointMake(100, 100);
}];
(animatedView是一个与IBOutlet连接的简单UIView)。
int myInt = 10;
NSMutableString* mString = [NSMutableString stringWithString:@"Mutable Hello"];
NSString* imString = @"Imutable Hello";
void (^myBlock)(void) = ^
{
[mString appendString:@" Block"]; //working
imString = @"Imutable Hello Block"; //error
myInt = 11; //error
};
我的问题是:为什么我可以为UIView实例属性赋值?
我没有解决对象并更改它,就像我的mString一样。
我希望'center'属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针。
我希望'backgroundColor'的行为类似于我的imString,因为它是一个指向一个新对象的对象的指针,不是吗?
我在文档中找不到令人满意的解释...如果有人可以提供一个,或者说我一个人,我将不胜感激。
答案 0 :(得分:8)
这是分配和使用之间的区别。用法是方法调用。您完全被允许在实例([mString appendString:@" Block"]; //working
)上调用方法,但是您无法在不标记变量的情况下分配(imString = @"Imutable Hello Block"; //error
)以告诉编译器它应该启用它。
此代码:
self.animatedView.backgroundColor = [UIColor blueColor];
仍然不是一个真正的赋值,它是一个'隐藏'方法调用。点符号永远不是一个赋值,它是方法调用的语法糖。它实际上转换为:
[[self animatedView] setBackgroundColor:[UIColor blueColor]];
分配给局部变量和对象内部变量的区别在于它们驻留在内存中的位置。基本上,它们的存在时间是否足够长。这是堆栈上和堆上的数据之间的区别。
答案 1 :(得分:3)
要允许在块中更改变量,请使用_ 块存储类型修饰符 - 请参阅“ _block Storage Type。”
__block NSString* imString = @"Imutable Hello";
引用
以下规则适用于块中使用的变量:
它们的值是在程序中的块表达式处获取的。在嵌套块中,从最近的封闭范围捕获值。
使用__block存储修饰符声明的封闭词法范围的局部变量由引用提供,因此是可变的。
任何更改都会反映在封闭的词法范围中,包括在相同的封闭词法范围内定义的任何其他块。这些将在“The __block Storage Type”中详细讨论。
在块的词法范围内声明的局部变量,其行为与函数中的局部变量完全相同。
答案 2 :(得分:3)
在你的第一个例子中,块"捕获"变量 self - 这是一个指向可保留对象的指针。当你写下来时,你不会在你的例子中修改 self :
self.someProperty = someValue;
self 的值仍然保持不变 - 也就是说,它仍然指向同一个对象。
您可以修改 self ,例如,如果您写:
self = nil;