为什么在避免块保留周期时使用typeof()而不是对象类型?

时间:2014-11-08 16:36:15

标签: objective-c

当其他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方法。如果selfObjTwoAwesomeObj的实例,则上面的假代码应该可以正常工作。

1 个答案:

答案 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"];