Are you really sure on how to declare a block? How about all 4 variations? On iOS and macOS, it can be easy to forget Objective-C block syntax as it isn’t the most intuitive, especially now Swift is becoming the main language of new projects. Remembering the syntax is actually just a short click away but here are easy-to-read example uses with nullability tips and things to watch out for when declaring a block.
Examples
Declaring a block as a property called completion on an object:
@property (nonatomic, copy, nullable) void (^completion)(BOOL success, NSError *error);
Declaring a method that accepts a block called completion:
- (void)animateWithCompletion:(void (^_Nullable)(BOOL animated))completion;
Declaring a block for use in an argument to the method defined above:
[self animateWithCompletion:^(BOOL animated) {
// Great code
if (animated) {
// Do something
}
}];
Declaring a block as a local variable called numberCrunch:
int (^_Nonnull numberCrunch)(int, int) = ^int (int a, int b) {
// Do clever number Maths
return 42;
};
int answer_to_life = numberCrunch(2, 4);
Nullability
If you’re not using nullability in your Objective-C project, just strip out the keywords otherwise use the underscore versions _Nonnull and _Nullable with the block pointers. If you’re declaring a block as a property on an object you can use the nullable and nonnull versions.
Retaining
It is worth remembering blocks capture and retain the objects used inside them and copy the values of primitive types (int, float, etc). You can release them by releasing the block (either through nilling the property or letting it leave the scope if it is an instance variable).
If you access the object the block is a property of i.e. by calling self in the block, then as the object retains the block… the block will retain any referenced objects. This creates a retain-cycle so the self object would never get released. This only happens when the block is a property of the self object but it is considered good practice to use a weak variable to reference self to avoid this situation. You can also enable a build setting for LLVM in your Xcode Project to flag “Implicit retain of ‘self’ within blocks” as a warning.
__weak typeof(self) weakSelf = self;
[self animateWithCompletion:^(BOOL animated) {
// Only use weakSelf
[weakSelf doSomething];
}];
That is everything for now. I’ll be posting some advanced tips and tricks for using blocks later including: –
- Building a block completion queue
- Things to watch when using blocks in UI views
- Using a typedef for blocks to simplify protocols dramatically