web-dev-qa-db-ja.com

名前によるクロージャ構文で作成されたNotificationCenterオブザーバーを削除することは適切ですか?

次のようなブロック/末尾のクロージャ構文を使用して作成された通知がいくつかあります。

NotificationCenter.default.addObserver(forName: .NSManagedObjectContextObjectsDidChange, object: moc, queue: nil) { note in
    // implementation
}

このように、後で名前で削除しました。

NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSManagedObjectContextObjectsDidChange, object: moc)

私の質問

これで十分ですか?または、NSObjectProtocolを独自のプロパティに保存し、次の構文でそのプロパティを削除する必要がありますか?

NotificationCenter.default.removeObserver(didChangeNotification)
11
Dan Beaulieu

戻り値をプロパティに格納し、後で削除する必要があります。

から https://developer.Apple.com/reference/foundation/nsnotificationcenter/1411723-addobserverforname

戻り値

オブザーバーとして機能する不透明なオブジェクト。

removeObserverメソッドのいずれかを呼び出す場合、最初のパラメーターは削除するオブザーバーです。通知に応答するようにブロックを設定すると、selfnotオブザーバーであり、NSNotificationCenterはバックグラウンドで独自のオブザーバーオブジェクトを作成し、それをユーザーに返します。 。

:iOS 9以降、removeObserver/deallocからdeinitを呼び出す必要はなくなりました。これは、オブザーバーが離れると自動的に行われるためです。したがって、iOS 9のみをターゲットにしている場合、これはすべて正常に機能する可能性がありますが、返されたオブザーバーをまったく保持していない場合は、予期する前に通知が削除される可能性があります。転ばぬ先の杖。

12
Dave Weston

@Daveの回答に追加すると、ドキュメントが常に100%正確であるとは限らないようです。 Ole Begemannによるこの記事 によると、ドキュメントには矛盾があり、iOS 11.2の時点で彼の テストアプリ では自己削除の魔法は発生していませんでした。

そのため、答えは「はい、そのオブザーバーを手動で削除する必要があります」です(そして、はい、selfはオブザーバーではなく、addObserver()メソッドはオブザーバーです)。

4
Vitalii

正しい実装がどのように見えるかについてのコードの例を次に示します。

クラスA(通知の受信者またはオブザーバー)にオブザーバーを追加したときに返される変数を宣言します。

private var fetchTripsNotification: NSObjectProtocol?

Initメソッドで、自分自身をオブザーバーとして追加します。

init() {
    fetchTripsNotification = NotificationCenter.default.addObserver(forName: .needsToFetchTrips, object: nil, queue: nil) { [weak self] _ in
        guard let `self` = self else {
            return
        }
        self.fetchTrips()
    }
}

クラスのdeinitメソッドで、必ずオブザーバーを削除してください。

deinit { NotificationCenter.default.removeObserver(fetchTripsNotification as Any) }

クラスB(通知の投稿者)で、通常のように通知をトリガーします。

NotificationCenter.default.post(name: .needsToFetchTrips, object: nil)
1