私はまだObjective-cのブロックに慣れておらず、この擬似コードが正しいかどうか疑問に思っています。オブザーバーを削除するだけで十分かどうか、またはremoveObserver:name:object:を呼び出す必要があるかどうかはわかりません。
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
id scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
更新:このブロックから断続的なEXC_BAD_ACCESS
を受信しているため、これは正しくありません。
ブロック自体を定義する前に、scanComplete
変数を宣言します。
これを行う必要がある理由は、変数自体がまだ割り当てられていないため、定義時にブロック内に存在しない変数にアクセスしようとしているためです。
とは EXC_BAD_ACCESS
?まあ、それは存在しない参照にアクセスしようとしたときにスローされる例外です。だからあなたの例ではまさにそうです。
したがって、ブロック自体の前に変数を宣言すると、次のように機能するはずです。
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
__block id scanComplete;
scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
登録ブロックで登録を解除しないでください。代わりに、addObserverForName
(この場合はscanComplete
)から返されたトークンをインスタンス変数またはインスタンス変数であるコレクションに保存し、後で登録を解除します。存在しない(例:dealloc
)。私がしているのは、observers
というNSMutableSetを保持することです。そう:
id ob = [[NSNotificationCenter defaultCenter]
addObserverForName:@"whatever" object:nil queue:nil
usingBlock:^(NSNotification *note) {
// ... whatever ...
}];
[self->observers addObject:ob];
そして後で:
for (id ob in self->observers)
[[NSNotificationCenter defaultCenter] removeObserver:ob];
self->observers = nil;
この方法に関するAppleドキュメント:
次の例は、ロケール変更通知を受信するために登録する方法を示しています。
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
self.localeChangeObserver = [center addObserverForName:NSCurrentLocaleDidChangeNotification object:nil
queue:mainQueue usingBlock:^(NSNotification *note) {
NSLog(@"The user's locale changed to: %@", [[NSLocale currentLocale] localeIdentifier]);
}];
オブザベーションの登録を解除するには、このメソッドによって返されたオブジェクトをremoveObserver:に渡します。あなた必須 addObserverForName:object:queue:usingBlock:で指定されたオブジェクトの割り当てが解除される前に、removeObserver:またはremoveObserver:name:object:を呼び出します。
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self.localeChangeObserver];