NSNotificationCenterでオブジェクトを渡す方法


129

アプリのデリゲートから別のクラスの通知レシーバーにオブジェクトを渡そうとしています。

整数を渡したいmessageTotal。今私は持っています:

レシーバー:

- (void) receiveTestNotification:(NSNotification *) notification
{
    if ([[notification name] isEqualToString:@"TestNotification"])
        NSLog (@"Successfully received the test notification!");
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissSheet) name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveTestNotification:) name:@"eRXReceived" object:nil];

通知を行っているクラスで:

[UIApplication sharedApplication].applicationIconBadgeNumber = messageTotal;
[[NSNotificationCenter defaultCenter] postNotificationName:@"eRXReceived" object:self];

しかし、オブジェクトmessageTotalを他のクラスに渡したいです。


SWIFT 2.0およびSWIFT 3.0のstackoverflow.com/questions/36910965/...
サヒール

回答:


235

"userInfo"バリアントを使用して、messageTotal整数を含むNSDictionaryオブジェクトを渡す必要があります。

NSDictionary* userInfo = @{@"total": @(messageTotal)};

NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:@"eRXReceived" object:self userInfo:userInfo];

受信側では、次のようにuserInfo辞書にアクセスできます。

-(void) receiveTestNotification:(NSNotification*)notification
{
    if ([notification.name isEqualToString:@"TestNotification"])
    {
        NSDictionary* userInfo = notification.userInfo;
        NSNumber* total = (NSNumber*)userInfo[@"total"];
        NSLog (@"Successfully received test notification! %i", total.intValue);
    }
}

おかげでmessageTotal、UIButtonでバッジを設定しています。新しいバッジ数でボタンを更新する方法を知っていますか?画像を表示するためのコードがviewDidLoadあるUIBarButtonItem *eRXButton = [BarButtonBadge barButtonWithImage:buttonImage badgeString:@"1" atRight:NO toTarget:self action:@selector(eRXButtonPressed)];
ジョン

notification.nameを比較する必要がある理由がわかりません。名前のマッピングは、addObserver()を実行するときに実行する必要があります。receiveTestNotificationは、特定の通知を監視する場合にのみ呼び出す必要があります。
Johan Karlsson

1
ヨハン、この単純なケースでは正しいですが、複数の通知が同じハンドラーをトリガーすることが可能です
Lytic

93

独自のカスタムデータオブジェクトを渡す例を示すと便利だと考えた場合のソリューションに基づいて構築しました(質問ごとにここでは「メッセージ」として参照しています)。

クラスA(送信者):

YourDataObject *message = [[YourDataObject alloc] init];
// set your message properties
NSDictionary *dict = [NSDictionary dictionaryWithObject:message forKey:@"message"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationMessageEvent" object:nil userInfo:dict];

クラスB(レシーバー):

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(triggerAction:) name:@"NotificationMessageEvent" object:nil];
}

#pragma mark - Notification
-(void) triggerAction:(NSNotification *) notification
{
    NSDictionary *dict = notification.userInfo;
    YourDataObject *message = [dict valueForKey:@"message"];
    if (message != nil) {
        // do stuff here with your message data
    }
}

2
なぜこの回答に賛成票がないのですか?それは完全に機能し、ハックではありません!
Reuben Tanner 14

4
@Kairosは、このように使用するように設計されていないためです。のobjectパラメータは、postNotificationName この通知を送信するパラメータを意味する必要があります。
xi.lin

2
はい、オブジェクトはuserInfoparamを使用してNSDictionaryとして渡される必要があり、上記の受け入れられた回答はこれを表示するように編集されています。
デビッドダグラス

1
これは非常に誤解を招きやすいのですが、なぜその回答には多くの賛成票があるのですか?これは削除する必要があります。誰もがこのために作成されたuserInfoを使用する必要があります。
2016年

わかりました、フィードバックに感謝します... userInfoオブジェクトのデータを渡す方法として辞書を使用するように答えを更新しました。
David Douglas

27

Swift 2バージョン

@Johan Karlssonが指摘したように...私はそれを間違っていました。NSNotificationCenterで情報を送受信する適切な方法は次のとおりです。

まず、postNotificationNameのイニシャライザを確認します。

init(name name: String,
   object object: AnyObject?,
 userInfo userInfo: [NSObject : AnyObject]?)

ソース

userInfoparam を使用して情報を渡します。[NSObject : AnyObject]タイプは、ホールドオーバーからであるObjective-Cの。したがって、Swiftランドでは、派生するキーNSObjectとにできる値を持つSwift辞書を渡すだけで済みますAnyObject

その知識を基に、objectパラメーターに渡す辞書を作成します。

 var userInfo = [String:String]()
 userInfo["UserName"] = "Dan"
 userInfo["Something"] = "Could be any object including a custom Type."

次に、ディクショナリをオブジェクトパラメータに渡します。

送信者

NSNotificationCenter.defaultCenter()
    .postNotificationName("myCustomId", object: nil, userInfo: userInfo)

レシーバークラス

最初に、クラスが通知を監視していることを確認する必要があります

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("btnClicked:"), name: "myCustomId", object: nil)   
}
    

次に、辞書を受け取ります。

func btnClicked(notification: NSNotification) {
   let userInfo : [String:String!] = notification.userInfo as! [String:String!]
   let name = userInfo["UserName"]
   print(name)
}

実際には、postNotificationName()の使用目的に違反しています。しかし、あなたは一人ではありません。ユーザーオブジェクトを送信するためにオブジェクトパラメータを使用する多くの開発者を見てきました。2番目の引数であるオブジェクトは、送信者用に予約されています。すべての種類のオブジェクトを送信するには、userInfoを実際に使用する必要があります。そうしないと、などのランダムなクラッシュが発生することがあります
ヨハン・カールソン

25

スウィフト5

func post() {
    NotificationCenter.default.post(name: Notification.Name("SomeNotificationName"), 
        object: nil, 
        userInfo:["key0": "value", "key1": 1234])
}

func addObservers() {
    NotificationCenter.default.addObserver(self, 
        selector: #selector(someMethod), 
        name: Notification.Name("SomeNotificationName"), 
        object: nil)
}

@objc func someMethod(_ notification: Notification) {
    let info0 = notification.userInfo?["key0"]
    let info1 = notification.userInfo?["key1"]
}

ボーナス(絶対にやるべきこと!):

交換するNotification.Name("SomeNotificationName").someNotificationName

extension Notification.Name {
    static let someNotificationName = Notification.Name("SomeNotificationName")
}

"key0"and "key1"Notification.Key.key0andを置き換えますNotification.Key.key1

extension Notification {
  enum Key: String {
    case key0
    case key1
  }
}

なぜこれを確実に行う必要があるのですか?コストのかかるタイプミスを避けるために、名前の変更を楽しんだり、使用法を見つけたりして楽しんでください...


ありがとう。どうやらNotification.Nameを拡張することは可能ですが、Notification.Keyは拡張できません。 'Key' is not a member type of 'Notification'。こちらをご覧ください:ご覧ください https
//ibb.co/hDQYbd2

ありがとう、それKey以来structは削除されているようです。私は答えを更新しています
frouo

1

Swift 5.1カスタムオブジェクト/タイプ

// MARK: - NotificationName
// Extending notification name to avoid string errors.
extension Notification.Name {
    static let yourNotificationName = Notification.Name("yourNotificationName")
}


// MARK: - CustomObject
class YourCustomObject {
    // Any stuffs you would like to set in your custom object as always.
    init() {}
}

// MARK: - Notification Sender Class
class NotificatioSenderClass {

     // Just grab the content of this function and put it to your function responsible for triggering a notification.
    func postNotification(){
        // Note: - This is the important part pass your object instance as object parameter.
        let yourObjectInstance = YourCustomObject()
        NotificationCenter.default.post(name: .yourNotificationName, object: yourObjectInstance)
    }
}

// MARK: -Notification  Receiver class
class NotificationReceiverClass: UIViewController {
    // MARK: - ViewController Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Register your notification listener
        NotificationCenter.default.addObserver(self, selector: #selector(didReceiveNotificationWithCustomObject), name: .yourNotificationName, object: nil)
    }

    // MARK: - Helpers
    @objc private func didReceiveNotificationWithCustomObject(notification: Notification){
        // Important: - Grab your custom object here by casting the notification object.
        guard let yourPassedObject = notification.object as? YourCustomObject else {return}
        // That's it now you can use your custom object
        //
        //

    }
      // MARK: - Deinit
  deinit {
      // Save your memory by releasing notification listener
      NotificationCenter.default.removeObserver(self, name: .yourNotificationName, object: nil)
    }




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