SwiftのNSNotificationのオブザーバーをどこで削除しますか?


83

とが利用できないNSNotificationので、Swiftのオブザーバーをどこで削除する必要がありますか?viewDidUnloaddealloc()


最近では、ブロックスタイルを使用していない限り、手動で削除する必要はありません
Fattie

回答:


71

と同じように機能する以下の方法を使用しますdealloc

deinit {
    // Release all resources
    // perform the deinitialization
}

デイニシャライザーは、クラスインスタンスの割り当てが解除される直前に呼び出されます。初期化子をinitキーワードで記述するのと同様に、初期化解除子をdeinitキーワードで記述します。デイニシャライザーは、クラスタイプでのみ使用できます。

Swift Deinitializer


12
iOS 9以降、以下の回答によると、ブロックベースのオブザーバーを使用していない限り、オブザーバーは自動的に削除されます。
Crashalot 2017

ViewControllerAの@Kampaideinitメソッドは、ViewControllerBをプッシュするときに呼び出されません。
アニルダマハレ2018

@ AnirudhaMahale-いいえ、ViewControllerAはまだナビゲーションコントローラーのスタックにあるためです。deinitfor ViewControllerAは、ナビゲーションコントローラーのスタックにない場合にのみ呼び出されます。たとえば:rootViewController(rootViewControllerがViewControllerAない場合)への切り替え
Kampai

@Kampai:これはViewControllerにオブザーバーを追加する場合とは異なります。保持サイクルでキャッチされ、まったく呼び出さdeinitれない可能性が高くなります。電話をかけるのに理想的な場所func viewDidDisappear(_ animated: Bool)
BhanuBirani18年

@BhanuBirani:「ハイチャンス」について言及しているケースについて説明していただけますか。まあ私の経験では、私は何にも直面していませんでした。
カンパイ2018年

135

以下のようiOSの9(およびOS X 10.11)、あなたはオブザーバーに削除する必要はありませんあなたはかかわらず、ブロックベースのオブザーバーを使用していない場合は、自分自身を。システムは、可能な場合、オブザーバーに対してゼロ化弱参照を使用するため、これを実行します。

また、ブロックベースのオブザーバーを使用している場合は、クロージャーのキャプチャリストを使用して自己を弱く[weak self]キャプチャし、メソッドでオブザーバー削除してくださいdeinit。自己への弱い参照を使用しない場合deinit、通知センターはそれへの強い参照を無期限に保持するため、メソッド(したがってそのオブザーバーの削除)が呼び出されることはありません。

詳細については、OS Xv10.11およびiOS9のFoundationリリースノートを参照してください。

オブザーバーをゼロ化弱参照として格納できる場合、基になるストレージはオブザーバーをゼロ化弱参照として格納します。または、オブジェクトを弱く格納できない場合(つまり、ランタイムを妨げるカスタムの保持/解放メカニズムがある場合)オブジェクトを弱く格納できることから)オブジェクトを弱でないゼロ参照として格納します。これは、オブザーバーが割り当て解除方法で登録を解除する必要がないことを意味します。

-[NSNotificationCenter addObserverForName:object:queue:usingBlock]メソッドを介したブロックベースのオブザーバーは、システムがこれらのオブザーバーへの強力な参照を保持しているため、使用されなくなったときに登録を解除する必要があります。


1
私は興味があります、それは代表者にとって同じように機能しますか?iOS8で見たように、デリゲートはメモリを占有し、保持しません。以前delegate = nildealloc()メソッドを書き込んでいました。これからも同じように動作しますか?
カンパイ2018年

1
原則として、デリゲートは弱参照として宣言する必要があり、他の作業は必要ありません。
ニコラミリチェビッチ2018年

ブロックベースのオブザーバーでは機能しないと具体的に述べたので、その理由を詳しく説明していただけますか?それを回避する方法はありますか?例[弱い自己]
フィリップジャホダ2018年

62

次の3つの方法を使用できます。

  1. popViewController、戻る、navigationControllerまたはdismissViewControllerAnimated

    deinit {
        print("Remove NotificationCenter Deinit")
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
  2. viewDidDisappear、それがすでに次のビューコントローラになった後で削除します。

    override func viewDidDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
  3. viewWillDisappear -次のビューを開く前に:

    override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    

Swift 3.0構文:

NotificationCenter.default.removeObserver(self)

1
ここではdeinitが最良のオプションだと思います。
グレンポサダス2016年

iOS 9以降、@ Nikola Milicevicによると、ブロックベースのオブザーバーを使用していない限り、オブザーバーは自動的に削除されます。
Crashalot 2017

コントローラーを離れるときにオブザーバーを削除すると、オブザーバーを持つという目的が損なわれますか?また、deinitは、ストーリーボードを使用せずにプログラムで1つのクラスから別のクラスに移動する場合にのみ機能しますか?
シリル

18

Swift 4.2では、これはオブザーバーを削除する方法の1つです

deinit {
    NotificationCenter.default.removeObserver(self, name: Notification.Name.Identifier, object: nil)
}

viewDidLoadクラスでaddObserver通知を設定します

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(didReceivedItemDetail), name: Notification.Name.Identifier, object: nil)
}

2
低速のネットワーク状態および特定のユーザーアクティビティ、つまりビジービューアクション中にナビゲートする場合、deinitが呼び出されない場合があることに注意してください。私はこれをテストで見ました。
GordonW

2
@GordonWビューコントローラのライフサイクルの最後にdeinitメソッドが呼び出されない場合は、そのクラスにメモリの問題があります。
Ashim Dahal


4

また、この方法を使用する必要があることも指摘しておきます。

func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?, object anObject: Any?)

の代わりに

func addObserver(forName name: NSNotification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol

後者はオブザーバーを削除しません(最近この問題に遭遇しました)。iOS9を使用している場合、前者はオブザーバーを削除します。


前者はいつオブザーバーを削除しますか?
Shubham 2017年


これは、2番目のメソッドで保持サイクルがあり、メソッドでオブザーバーを手動で削除しなかったためだと思いますdealloc
NikKov18年


0

オブザーバーを追加しviewWillAppear()たり削除したりするのも良いことですviewWillDisappear()


0

スウィフト5

私はチャットアプリケーションを持っているので、ChatLogViewControllerから他のviewControllerに移動してから戻ってくるたびに、キーボード通知のオブザーバーが1つ追加されます。これを削除するには、viewControllerを変更するか、chatLogViewControllerから消えるときに、すべてのオブザーバーを削除します。

override func viewDidDisappear(_ animated: Bool) {    
    super.viewDidDisappear(animated)

    NotificationCenter.default.removeObserver(self)
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.