I have seen this code snippet frequently when other ObjC developer are breaking a retain cycle.
__weak typeof(self) weakSelf = self;
[someObject doThingWithCompletion:^{
typeof(weakSelf) strongSelf = weakSelf;
[strongSelf awesomeThingOne];
[strongSelf moreAwesome];
}];
Why the use of the typeof()
macro? Is this unique to blocks?
My initial thought is that self
's type might not be known (that seems mostly impossible, but let's pretend...). If the type is unknown, then why not declare weakSelf
with an id
: __weak id weakSelf = self;
?
My second thought is that it's defensive against subclassing, but that seems unlikely to cause an issue. Assume ObjTwo
subclasses AwesomeObj
and overrides the awesomeThingOne
method. The fake code above should work just fine if self
is an instance of ObjTwo
or AwesomeObj
.
The typeof()
macro allows a few things.
First of all, personally, I've created a code snippet with this sort of thing. Instead of having to type out:
__weak MyClass *weakSelf = self;
each and every time I want to set this up, substituting MyClass
for the appropriate class, I can instead just start to type weakSelf
and Xcode's autocomplete will try to offer my this line of code:
__weak typeof(self) weakSelf = self;
That's going to work every time.
Also, using typeof()
gives us an explicit type and minimizes the code to rewrite if we ever change the actual type.
id
is unsafe and it won't give us auto-completes on available methods and properties. After all, weakSelf
is now of type id
rather than of type MyClass
.
And we can run into the same problem with subclasses where if I just default to MyClass
, doing:
weak MyClass *weakSelf = self;
won't give me autocompletes on methods/properties that MySubClass
added if self
is actually MySubClass
.
And use of typeof()
isn't at all limited to blocks. I like to use typeof()
in class methods.
Generally, the following is sufficient:
+ (instancetype)myInstance {
return [[self alloc] init];
}
As instancetype
and [self alloc]
take care of getting the right subclass.
But suppose we want something more complex:
+ (NSMutableArray *)arrayOfInstances;
How can we make sure the objects we stick into the array are of the right type?
+ (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;
}
We wouldn't want to use id
as the type for newObj
. We want to be certain that if we call:
[MyClass arrayOfInstances];
We get an array of MyClass
objects, but if we call:
[MySubClass arrayOfInstances];
We get an array of MySubClass
objects, etc.
We could also use typeof()
if we wanted to instantiate an object from a dictionary that defined our object:
Class dynamicType = myDict[@"Class"];
typeof([dynamicType alloc]) myObject = [[dynamicType alloc] init];
myObject.foo = myDict[@"Foo"];
myObject.bar = myDict[@"Bar"];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With