当其他ObjC开发人员打破保留周期时,我经常看到这段代码。
__weak typeof(self) weakSelf = self;
[someObject doThingWithCompletion:^{
typeof(weakSelf) strongSelf = weakSelf;
[strongSelf awesomeThingOne];
[strongSelf moreAwesome];
}];
为什么要使用typeof()
宏?这是块的独特之处吗?
我最初的想法是self
的类型可能不知道(这似乎大多不可能,但让我们假装......)。如果类型未知,那么为什么不用weakSelf
声明id
:__weak id weakSelf = self;
?
我的第二个想法是它对子类化的防御,但这似乎不太可能导致问题。假设ObjTwo
子类AwesomeObj
并覆盖awesomeThingOne
方法。如果self
是ObjTwo
或AwesomeObj
的实例,则上面的假代码应该可以正常工作。
答案 0 :(得分:7)
typeof()
宏允许一些事情。
首先,就个人而言,我已经创建了一个包含这类内容的代码片段。而不是输入:
__weak MyClass *weakSelf = self;
每次我想要设置它时,用MyClass
代替相应的类,我只能开始输入weakSelf
,Xcode的自动完成将尝试提供我的这行代码:
__weak typeof(self) weakSelf = self;
每次都会发挥作用。
此外,使用typeof()
为我们提供了一个显式类型,并且如果我们改变实际类型,则最小化要重写的代码。
id
不安全,它不会让我们自动完成可用的方法和属性。毕竟,weakSelf
现在属于id
类型,而不是类型MyClass
。
我们可以遇到与子类相同的问题,如果我只是默认为MyClass
,那么:
weak MyClass *weakSelf = self;
如果MySubClass
实际为self
,则不会自动填充MySubClass
添加的方法/属性的自动填充。
使用typeof()
并不仅限于块。我喜欢在类方法中使用typeof()
。
通常,以下内容就足够了:
+ (instancetype)myInstance {
return [[self alloc] init];
}
由于instancetype
和[self alloc]
负责获得正确的子类。
但是假设我们想要更复杂的东西:
+ (NSMutableArray *)arrayOfInstances;
我们如何确保我们在数组中保留的对象属于正确的类型?
+ (NSMutableArray *)arrayOfInstances {
NSMutableArray *instances = [NSMutableArray array];
for (int i = 0; i < 10; ++i) {
typeof([self alloc]) newObj = [[self alloc] init];
newObj.someIntProperty = i;
[instances addObject:newObj];
}
return instances;
}
我们不希望将id
用作newObj
的类型。我们希望确定如果我们致电:
[MyClass arrayOfInstances];
我们得到一组MyClass
个对象,但如果我们调用:
[MySubClass arrayOfInstances];
我们得到一组MySubClass
个对象等
如果我们想要从定义对象的字典中实例化一个对象,我们也可以使用typeof()
:
Class dynamicType = myDict[@"Class"];
typeof([dynamicType alloc]) myObject = [[dynamicType alloc] init];
myObject.foo = myDict[@"Foo"];
myObject.bar = myDict[@"Bar"];