[iOS] Pointer to Block Pointer
November 24, 2011 at 10:34 pm Tinggalkan Komentar
iOS block programming feature is pretty cool, it makes asynchronous programming easier. This time I want to talk about block pointer. A block pointer is a type of variable that we can use to refer to a block, for example
void (^blockPointer)(void) = void ^(void) { NSLog(@"inside a block"); };
We can then execute the block like normal function call.
blockPointer();
What’s interesting is that a block pointer is actually an Objective-C object. We can do copy, retain, release, autorelease (more on this can be read here) on it, and also assign a pointer to it
.
I’ll show you a sample use case where I want to make a pointer to a block pointer. Suppose I have a function that does something asynchronously and executes a block at the end of it.
- (void) asyncFunction:(void (^)(void)) block {
// do something asynchronously, then execute the block at the end
block();
}
Then I have another function, a nasty one with many nested ifs, that passes a block to asyncFunction depending on the conditions. When it doesn’t call asyncFunction, the block still has to be executed. So the block must be called exactly once, no matter which conditional route it takes.
Solution A: do some brute force with myriads of if-else
- (void)nastyFunction:(void (^)(void)) block {
if (...) {
if (...) {
[self asyncFunction:block];
} else {
/* myriads of other if-else */
}
} else (...) {
block();
}
}
Solution B: Because a block pointer is an Objective-C object, we can assign nil to it. So after calling asyncFunction, we assign the block to nil. At the end of nastyFunction we execute the block only if it’s not nil.
- (void)nastyFunction:(void (^)(void)) block {
if (...) {
if (...) {
[self asyncFunction:block];
block = nil;
}
/* myriads of other ifs */
}
if (block != nil){
block();
}
}
The number of else decreases, the number of ‘block = nil‘ increases.
Solution C: this is where pointer to block pointer becomes useful. Instead of writing ‘block=nil‘ numerous times, we write it only once inside asyncFunction. But to change the value of block inside nastyFunction, we have to pass it to asyncFunction using a pointer. We declare a pointer to block pointer using this statement.
void (^pointerToBlockPointer *)(void)
So asyncFunction becomes
- (void) asyncFunction:(void (^*)(void)) block {
// do something asynchronously, then execute the block at the end and assign it to nil
*block();
*block = nil;
}
And we pass the block from nastyFunction using its address.
- (void)nastyFunction:(void (^)(void)) block {
if (...) {
if (...) {
[self asyncFunction:&block];
}
/* myriads of other ifs */
}
if (block != nil){
block();
}
}
The declaration for pointer to block pointer is pretty funny, I got it from XCode compilation error message
.
Another useful tips: if you want to simplify the declaration, you can typedef the block pointer.
typedef (void)(^BlockPointerType)(void);
So the pointer to it can be written as
BlockPointerType * pointerToBlockPointer;
Entry filed under: Programming. Tags: apple, block, ios, objective-c, pointer, xcode.
Trackback this post | Subscribe to the comments via RSS Feed