You can solve this in a general way, without have to create specific block iVars in all controllers. You could create a class provides "when done" block processing, and then just inherit from it, and your view controllers will all have "when done" ability. You can just set the property or provide a "convenience" method.
Note, the original code for this first piece was just broken, so I changed it. -- Ugh. How embarrassing. Anyway, you get the idea (and I only suggest this if you are one who abhors associations).
// Use this as a base class for your view controllers...
typedef void(^WhenDoneWithViewControllerBlock)(
UIViewController *viewController,
BOOL canceled);
@interface BlockDismissingViewController : UIViewController
@property (nonatomic, strong) WhenDoneWithViewControllerBlock whenDone;
- (void)done:(BOOL)canceled;
@end
@implementation BlockDismissingViewController
- (void)done:(BOOL)canceled {
if (self.whenDone) {
self.whenDone(self, canceled);
}
}
@end
// The "convenience" method should probably be something like this...
@implementation UIViewController (BlockDismissingViewController)
- (void)presentViewController:(BlockDismissingViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion
whenDone:(WhenDoneWithViewControllerBlock)whenDone {
viewControllerToPresent.whenDone = whenDone;
[self presentViewController:viewControllerToPresent
animated:flag
completion:completion];
}
@end
Or, you could do it as a category on UIViewController, and now all your view controllers will get this functionality. You can use the notification center to invoke the appropriate block...
@interface UIViewController (WhenDoneWithViewControllerBlock)
- (void)done:(BOOL)canceled;
@end
@implementation UIViewController (WhenDoneWithViewControllerBlock)
- (void)presentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion
whenDone:(WhenDoneWithViewControllerBlock)doneBlock {
if (doneBlock) {
__block id observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"DoneWithViewControllerNotification"
object:viewControllerToPresent
queue:nil
usingBlock:^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
doneBlock(viewControllerToPresent, [[note.userInfo objectForKey:@"canceled"] boolValue]);
}];
}
[self presentViewController:viewControllerToPresent
animated:flag
completion:completion];
}
- (void)done:(BOOL)canceled {
[[NSNotificationCenter defaultCenter]
postNotificationName:@"DoneWithViewControllerNotification"
object:self
userInfo:@{ @"canceled" : @(canceled) }];
}
@end
Or, if you still want a category, but want an iVar and to bypass the notification center...
// Using associated objects in a category
@interface UIViewController (WhenDoneWithViewControllerBlock)
@property (nonatomic, strong) WhenDoneWithViewControllerBlock whenDone;
- (void)done:(BOOL)canceled;
@end
@implementation UIViewController (WhenDoneWithViewControllerBlock)
char const kWhenDoneKey[1];
- (WhenDoneWithViewControllerBlock)whenDone {
return objc_getAssociatedObject(self, kWhenDoneKey);
}
- (void)setWhenDone:(WhenDoneWithViewControllerBlock)whenDone {
objc_setAssociatedObject(self, kWhenDoneKey, whenDone, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)presentViewController:(UIViewController *)viewControllerToPresent
animated:(BOOL)flag
completion:(void (^)(void))completion
whenDone:(WhenDoneWithViewControllerBlock)whenDone {
viewControllerToPresent.whenDone = whenDone;
[self presentViewController:viewControllerToPresent animated:flag completion:completion];
}
- (void)done:(BOOL)canceled {
if (self.whenDone) {
self.whenDone(self, canceled);
}
}
@end
Of course, these are just examples, but hopefully you get the idea.
When your view controller is done, it just calls
[self done:canceledOrSuccess];
and the block will be invoked.
Using the last category is my favorite, even though there is a performance cost in both time and memory for associated objects. You get the convenience of an "iVar" that holds your "whenDone" block (you can set it explicitly), and you get the "convenience" method for presenting, and every view controller automatically gets this functionality, just by adding the category.