您可能想了解闭包的一般工作原理。
以下面的代码为例,
var name = "NSNoName"
NSLog("Original name: %@ <%p>", name, name)
let takeName: (String) -> Void -> () = {
name in
return {
NSLog("Name inside block: %@ <%p>", name, name)
}
}
let returnName = takeName(name)
name = "NSNoFame"
returnName()
NSLog("Changed name: %@ <%p>", name, name)
最初,name 变量的值为“NSNoName”。这时候打印名字,就得到了结果,
Original name: NSNoName <0x7f8fb86004a0>
我有一个简单的闭包,它将字符串作为参数。我用同名对象调用闭包,结果块创建了自己的对象副本。然后,我继续更改 name 对象,现在,如果我调用块来打印名称,则块具有传递给它的相同原始值。但是,对象不同,这意味着块创建了一个具有相同值的新对象。
Name inside block: NSNoName <0x7f8fb8602510>
最后一个 NSLog,打印一个不同的值,因为它已经改变并且有一些不同的值,
Changed name: NSNoFame <0x7f8fb8603ae0>
这就是你要告诉一个块,创建一个对该对象的弱引用的原因,这意味着如果原始对象不再存在,nil在块内创建的引用对象.
虽然使用 Objective C,但它似乎有点不同,
@interface TestViewController ()
@property (nonatomic, strong) NSString *name;
@end
@implementation TestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.name = @"NSNoName";
NSLog(@"Original name: %@ <%p>", self.name, self.name);
typedef void(^ReturnNameBlock)();
ReturnNameBlock (^takeName)(NSString*) = ^ReturnNameBlock(NSString *name) {
return ^{
NSLog(@"Name inside block: %@ <%p>", name, name);
};
};
ReturnNameBlock returnName = takeName(self.name);
self.name = @"NSNoFame";
returnName();
NSLog(@"Changed name: %@ <%p>", self.name, self.name);
}
@end
我的日志是这样的,
Original name: NSNoName <0x103ae34c0>
Name inside block: NSNoName <0x103ae34c0>
Changed name: NSNoFame <0x103ae3520>
如果您查看日志,该块拥有原始的 self.name 对象,因为两者具有相同的内存地址。虽然 viewController 不再拥有这个,但当我们更改 self.name = "NSNoFame" 时,该块仍然保留该对象的相同实例。
swift 和objective 的区别在于,Objective C 块保留传递给它的对象的原始实例,而 swift 闭包创建原始实例变量的副本。