SwiftのNSNotificationCenter addObserver


392

Swiftのオブザーバーをデフォルトの通知センターに追加するにはどうすればよいですか?バッテリーレベルが変化したときに通知を送信するこのコード行を移植しようとしています。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];

具体的に何を求めていますか?セレクターはどのように機能しますか?
nschum 2014年

1
「セレクター」タイプがSwiftの単なる文字列であることを知りませんでした。ドキュメントにはそれについての言及はありません。
Berry Blue

回答:


443

Objective-C APIと同じですが、Swiftの構文を使用しています。

Swift 4.2およびSwift 5:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.batteryLevelChanged),
    name: UIDevice.batteryLevelDidChangeNotification,
    object: nil)

オブザーバーがObjective-Cオブジェクトから継承しない場合@objc、セレクターとして使用するには、メソッドに接頭辞を付ける必要があります。

@objc private func batteryLevelChanged(notification: NSNotification){     
    //do stuff using the userInfo property of the notification object
}

NSNotificationCenter Class ReferenceObjective-C APIの操作を参照してください


3
ありがとう!Swiftでセレクター名を渡す方法がわかりませんでした。
Berry Blue

14
@BerryBlue、上記の解決策はうまくいきましたか?関数がNSNotificationをパラメーターとして受け入れる場合、「batteryLevelChanged」を「batteryLevelChanged:」に変更する必要があると思います。
オルシャンスク2014年

1
@オルシャンスクはい、あなたは正しいです。あなたはそれが必要です。ありがとう!
Berry Blue

なぜUIDeviceBatteryLevelDidChangeNotification引用符で囲まれていないのですか?文字列型です。
kmiklas 2014年

13
クラスまたはターゲットメソッドのいずれかにで注釈を付けてください@objc
Klaas 14

757

Swift 4.0およびXcode 9.0以降:

送信(投稿)通知:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

または

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])

受信(取得)通知:

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

受信した通知の関数メソッドハンドラ:

@objc func methodOfReceivedNotification(notification: Notification) {}

Swift 3.0およびXcode 8.0以降:

送信(投稿)通知:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

受信(取得)通知:

NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

受信した通知のメソッドハンドラ:

func methodOfReceivedNotification(notification: Notification) {
  // Take Action on Notification
}

通知を削除:

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

Swift 2.3およびXcode 7:

送信(投稿)通知

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

通知を受け取る(取得する)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)

受信した通知のメソッドハンドラー

func methodOfReceivedNotification(notification: NSNotification){
  // Take Action on Notification
}


Xcodeの過去のバージョンの場合...



送信(投稿)通知

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

通知を受け取る(取得する)

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)

通知を削除

NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self) // Remove from all notifications being observed

受信した通知のメソッドハンドラー

func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

クラスまたはターゲットメソッドに@objcで注釈を付ける

@objc private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

// Or

dynamic private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

21
クラスまたはターゲットメソッドのいずれかにで注釈を付けてください@objc
Klaas 14

1
@goofansuよろしいですか?純粋なSwiftクラスの場合は、追加する必要があると思います。
Klaas 14

10
methodOFReceivedNotication注釈を付けるかdynamic、NSObjectのサブクラスのメンバーである必要があります。
Klaas 14

1
そうでない場合、私は、実行時の警告を取得object 0x7fd68852d710 of class 'TestNotifications.MyObject' does not implement methodSignatureForSelector: -- trouble aheadUnrecognized selector -[TestNotifications.MyObject methodOFReceivedNotication:]
クラース

2
@TaylorAllred、私の回答のレビューをありがとうございました。私はあなたの提案に本当に感謝しています。変更しました。確認してください。
ダダニヤを2015

46

これを行う良い方法は、Objective-Cコードから頻繁に使用されるメソッドではaddObserver(forName:object:queue:using:)なく、メソッドを使用するaddObserver(_:selector:name:object:)ことです。最初のバリアントの利点は、@objcメソッドで属性を使用する必要がないことです。

    func batteryLevelChanged(notification: Notification) {
        // do something useful with this information
    }

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil,
        using: batteryLevelChanged)

必要に応じて、メソッドの代わりにクロージャを使用することもできます。

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil) { _ in print("🔋") }

戻り値を使用して、後で通知のリスニングを停止できます。

    NotificationCenter.default.removeObserver(observer)

このメソッドを使用すると別の利点がありました。これは、コンパイラーが静的にチェックできなかったため、メソッドの名前を変更すると壊れやすく、Swift 2.2および後でその問題を修正する#selectorを含めます。


7
これは素晴らしい!完全を期すために、登録解除の例も見たいと思います。addObserver(_:selector:name:object:) 登録解除の方法とはかなり異なります。オブジェクトを返して保持してaddObserverForName(_:object:queue:usingBlock:)渡す必要がありますremoveObserver:
Lucas Goossen

1
これは、によって返されたオブジェクトの登録解除を含むように更新する必要がありますaddObserverForName(_:object:queue:usingBlock:)
双曲線2016年

3
これは、Obj-C #selectorメソッドを使用する必要があるため、connorやRenishの(このコメントの時点では両方とも)よりもはるかに良い回答です。その結果、IMOはSwift-yより正確になりました。ありがとう!
patr1ck 2016

2
たとえば、これをa UIViewControllerで使用しself、そのクロージャーで参照する場合は、使用する必要があり[weak self]ます。そうしないと、参照サイクルとメモリリークが発生します。
Rob N

40

Xcode 8のSwift 3.0

Swift 3.0ではstruct、NotificationCenterと同様に、多くの「文字列型」のAPIが「ラッパー型」に置き換えられました。通知はではstruct Notfication.Nameなくによって識別されるようになりましたStringSwift 3へ移行ガイドをご覧ください。

以前の使用法:

// Define identifier
let notificationIdentifier: String = "NotificationIdentifier"

// Register to receive notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name: notificationIdentifier, object: nil)

// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationIdentifier, object: nil)

新しいSwift 3.0の使用法:

// Define identifier
let notificationName = Notification.Name("NotificationIdentifier")

// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification), name: notificationName, object: nil)

// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)

すべてのシステム通知タイプがで静的定数として定義されるようになりましたNotification.Name。すなわち.UIDeviceBatteryLevelDidChange.UIApplicationDidFinishLaunching.UITextFieldTextDidChange、など

Notification.Nameシステム通知との整合性を保つために、独自のカスタム通知で拡張できます。

// Definition:
extension Notification.Name {
    static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}

// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)

24
  1. 通知名を宣言する

    extension Notification.Name {
        static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
    }
  2. 次の2つの方法でオブザーバーを追加できます。

    使用する Selector

    NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: .purchaseDidFinish, object: nil)
    
    @objc func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }

    または使用 block

    NotificationCenter.default.addObserver(forName: .purchaseDidFinish, object: nil, queue: nil) { [weak self] (notification) in
        guard let strongSelf = self else {
            return
        }
    
        strongSelf.myFunction(notification: notification)
    }
    
    func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }
  3. 通知を投稿する

    NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])

iOS 9およびOS X 10.11から。NSNotificationCenterオブザーバが割り当て解除されたときに自身を登録解除する必要はなくなりました。より詳しい情報

以下のためにblockベースの実装、あなたが使用したい場合は弱の強いダンスをする必要がselfブロックの内側。より詳しい情報

ブロックベースのオブザーバーはより多くの情報を削除する必要があります

let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self.localeChangeObserver)

5
「iOS 9およびOS X 10.11から。NSNotificationCenterオブザーバーが割り当て解除時に自身を登録解除する必要がなくなりました。」 これは、セレクターベースのオブザーバーにのみ当てはまります。ブロックベースのオブザーバーはまだ削除する必要があります。
Abhinav

8

NSNotificationCenterを使用してデータを渡す

また、Swift 3.0ではNotificationCentreを使用し、Swift 2.0ではNSNotificationCenterを使用してデータを渡すこともできます。

Swift 2.0バージョン

タイプ[NSObject:AnyObject]のオプションのディクショナリであるuserInfoを使用して情報を渡しますか?

let imageDataDict:[String: UIImage] = ["image": image]

// Post a notification
 NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: imageDataDict)

// Register to receive notification in your class
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: notificationName, object: nil)

// handle notification
func showSpinningWheel(notification: NSNotification) {
  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

Swift 3.0バージョン

userInfoは[AnyHashable:Any]を取得しますか?引数として、Swiftで辞書リテラルとして提供します

let imageDataDict:[String: UIImage] = ["image": image]

// post a notification
 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
// `default` is now a property, not a method call

// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

// handle notification
func showSpinningWheel(_ notification: NSNotification) {

  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

NotificationCentre(swift 3.0)およびNSNotificationCenter(swift 2.0)を使用したソースパスデータ


それがあなたを助けたと聞いてうれしい:)
Sahil

6

ではスウィフト5

ViewControllerBからViewControllerAにデータを受信する場合を考えてみましょう

ViewControllerA(レシーバー)

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Code for Passing Data through Notification Observer - - - - -
        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: - - - - - Method for receiving Data through Post Notificaiton - - - - -
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB(送信者)

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Set data for Passing Data Post Notification - - - - -
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }

}

2

私は正常にセレクタを使用するには、次のいずれかの操作を行いすることができるよ- なし @objcで何かに注釈を付けるに:

NSNotificationCenter.defaultCenter().addObserver(self,
    selector:"batteryLevelChanged:" as Selector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

または

let notificationSelector: Selector = "batteryLevelChanged:"

NSNotificationCenter.defaultCenter().addObserver(self,
    selector: notificationSelector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

私のxcrunバージョンはSwift 1.2を示していますが、これはXcode 6.4およびXcode 7ベータ2(Swift 2.0を使用していると思っていました)で動作します。

$xcrun swift --version

Apple Swift version 1.2 (swiftlang-602.0.53.1 clang-602.0.53)

@objcオブザーバークラスがから継承する場合は、注釈を付ける必要はありませんNSObject
Antonio Favata

また、明示的にa Stringをキャストする必要はありませんSelector。:)
Antonio Favata

@alfvata:私のオブザーバークラスはNSObjectから継承しません。AnyObject、Swiftスタイルから継承します。文字列をセレクターに明示的にキャストすることで、他のObjective-C関連の回避策を回避することができます。
15

それがどのように機能するのか私にはわかりません。@objcNSObjectオブザーバークラスのメソッドからアノテーションを削除as Selectorし、Stringセレクター名にキャストを追加し、通知が発生するとアプリがクラッシュしました。私のSwiftバージョンはあなたのものとまったく同じです。
Antonio Favata 2015

3
@alfavata、何を言えばいいのかわかりません。現在Xcode Beta 4を使用していますが、まだ機能しています。私のプロジェクトは完全にSwiftです。Objective-Cコンポーネントはありません。多分それは違いを生みます。たぶんプロジェクトの設定が違うのかもしれません。可能性はいくつもあります!私は言います:@objc注釈が機能し、この方法が機能しない限り、注釈を付け続けてください!
15

2

SWIFT 2.2で- XCodeの7.3、我々は使用#selectorのためにNSNotificationCenter

 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)

2

通知も削除する必要があります。

deinit 
{
  NotificationCenter.default.removeObserver(self, name:NSNotification.Name(rawValue: "notify"), object: nil)

}

2
iOS 9以降、これは必要ないと思います。自動的に行われます。
Viktor Kucera 2017

1

Swift 3では、Xcode 8.2:-バッテリー状態レベルの確認

//Add observer
NotificationCenter.default.addObserver(self, selector: #selector(batteryStateDidChange), name: NSNotification.Name.UIDeviceBatteryStateDidChange, object: nil)


 //Fired when battery level changes

 func batteryStateDidChange(notification: NSNotification){
        //perform manipulation here
    }

1

NSNotificationCenteriOS 11のSwift 4.0にオブザーバー構文を追加

  NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

これは、keyboardWillShow通知名タイプ用です。利用可能なオプションから他のタイプを選択できます

セレクタは@objc func型で、キーボードの表示方法を処理します(これはユーザー関数です)


この答えを読んでいる人のために明確にするために:「セレクターはタイプ@objc func ...です」は、に関連付けられた関数に#selectorで注釈を付ける必要があることを意味します@objc。例:@objc func keyboardShow() { ... }Swift 4で1分間投げました!
傾斜

0

Swift 5およびXcode 10.2:

NotificationCenter.default.addObserver(
            self,
            selector: #selector(batteryLevelDidChangeNotification),
            name: UIDevice.batteryLevelDidChangeNotification,
            object: nil)

0

Swift 5通知オブザーバー

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelChanged), name: UIDevice.batteryLevelDidChangeNotification, object: nil)
}

@objc func batteryLevelChanged(notification : NSNotification){
    //do here code
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.batteryLevelDidChangeNotification, object: nil)

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