すべてのコントローラーで特定のブロックiVarを作成しなくても、一般的な方法でこれを解決できます。「完了時」のブロック処理を提供するクラスを作成し、それから継承するだけで、ビューコントローラはすべて「完了時」の機能を持ちます。プロパティを設定するか、「便利な」メソッドを提供するだけです。
この最初の部分の元のコードは壊れたばかりなので、変更しました。-うーん。恥ずかしい。とにかく、あなたはその考えを理解します(そして私はあなたが協会を嫌う人である場合にのみこれを提案します)。
// 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
または、UIViewControllerのカテゴリとして実行すると、すべてのViewControllerがこの機能を利用できるようになります。通知センターを使用して、適切なブロックを呼び出すことができます...
@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
または、カテゴリが必要であるが、iVarが必要で、通知センターをバイパスする場合...
// 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
もちろん、これらは単なる例ですが、うまくいけば、あなたはアイデアを得ることができます。
ビューコントローラが完了すると、それはただ呼び出します
[self done:canceledOrSuccess];
ブロックが呼び出されます。
関連するオブジェクトの時間とメモリの両方にパフォーマンスコストがかかりますが、最後のカテゴリを使用するのが私のお気に入りです。「whenDone」ブロックを保持する「iVar」の便利さ(明示的に設定できます)を取得し、表示するための「便利な」メソッドを取得します。すべてのView Controllerは、カテゴリを追加するだけで、この機能を自動的に取得します。