29

私はまだ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ので、これは正しくありません。

4

4 に答える 4

49

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];
}
于 2010-12-29T04:16:24.710 に答える
15

登録ブロックで登録を解除しないでください。addObserverForName代わりに、 (この場合は)から返されたトークンscanCompleteをインスタンス変数として、またはインスタンス変数であるコレクションに保存し、後で存在しなくなったときに(たとえば、dealloc)登録を解除します。私がしているのは、と呼ばれるNSMutableSetを保持することですobservers。それで:

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;
于 2011-11-23T18:56:11.680 に答える
3

この方法に関する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];
于 2015-06-01T02:10:03.820 に答える
-4

ブロックのスコープには、スキャナーオブジェクトを解放する権限がありません。ガベージコレクションを使用していない場合は、を削除しreleaseてスキャナーを自動解放([[[Scanner alloc] init] autorelease])にすることでうまくいくはずです。

removeObserverまた、通話をブロックの外に安全に移動できるはずです。

次の場合EXC_BAD_ACCESSbtアプリケーションがクラッシュした後にコンソールウィンドウに入ると、バックトレースが表示され、エラーが発生した場所が通知されます。

于 2010-12-29T09:21:18.133 に答える