วิธีการส่งผ่านวัตถุด้วย 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/…
Sahil

คำตอบ:


235

คุณจะต้องใช้ตัวแปร "userInfo" และส่งผ่านวัตถุ 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)];
Jon

ฉันไม่แน่ใจว่าทำไมคุณต้องเปรียบเทียบการแจ้งเตือน ควรทำการแมปชื่อเมื่อคุณทำ addObserver () getTestNotification ควรถูกเรียกเมื่อสังเกตการแจ้งเตือนเฉพาะเท่านั้น
Johan Karlsson

1
Johan ในกรณีง่าย ๆ นี้คุณถูกต้อง แต่ก็มีความเป็นไปได้ที่จะมีการแจ้งเตือนหลายรายการที่เรียกใช้ตัวจัดการเดียวกัน
Lytic

93

การสร้างโซลูชันให้ฉันคิดว่าอาจเป็นประโยชน์ในการแสดงตัวอย่างผ่านวัตถุข้อมูลที่กำหนดเองของคุณ (ซึ่งฉันได้อ้างอิงที่นี่เป็น 'ข้อความ' ตามคำถาม)

Class 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];

Class 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
ทำไมคำตอบนี้ไม่มี upvotes มากกว่านี้! มันทำงานได้อย่างสมบูรณ์แบบและไม่แฮ็ค!
รูเบนแทนเนอร์

4
@Kairos เพราะมันไม่ได้ถูกออกแบบมาให้ใช้แบบนี้ objectในพระรามpostNotificationName ควรหมายหนึ่งซึ่งส่งการแจ้งเตือนนี้
xi.lin

2
ใช่วัตถุควรถูกส่งเป็น NSDictionary โดยใช้userInfoพารามิเตอร์และคำตอบที่ได้รับการยอมรับด้านบนได้ถูกแก้ไขเพื่อแสดงสิ่งนี้
David Douglas

1
นี่เป็นสิ่งที่ทำให้เข้าใจผิดมากทำไมคำตอบนั้นมี upvotes มากมาย สิ่งนี้ควรถูกลบทิ้ง ทุกคนควรใช้ userInfo ซึ่งสร้างขึ้นสำหรับสิ่งนี้
Shinnyx

ตกลงขอบคุณสำหรับคำติชม ... ฉันได้อัปเดตคำตอบเพื่อใช้userInfoพจนานุกรมเป็นวิธีส่งผ่านข้อมูลของวัตถุ
David Douglas

27

เวอร์ชั่น Swift 2

@Johan Karlsson ชี้ให้เห็น ... ฉันทำผิดไป นี่คือวิธีที่เหมาะสมในการส่งและรับข้อมูลด้วย NSNotificationCenter

อันดับแรกเราดูที่ initializer สำหรับ postNotificationName:

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

แหล่ง

เราจะส่งผ่านข้อมูลของเราโดยใช้userInfoพารามิเตอร์ [NSObject : AnyObject]ประเภทคือการระงับจากObjective-C ดังนั้นในสวิฟท์แลนด์สิ่งที่เราต้องทำก็คือส่งผ่านพจนานุกรมสวิฟท์ที่มีกุญแจที่ได้มาNSObjectและค่าที่สามารถเป็น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 () อย่างตั้งใจ แต่คุณไม่ได้อยู่คนเดียว ฉันเห็นนักพัฒนาหลายคนใช้พารามิเตอร์ object สำหรับส่งวัตถุผู้ใช้ อาร์กิวเมนต์ที่สองคือวัตถุสงวนไว้สำหรับผู้ส่ง คุณควรใช้ userInfo เพื่อส่งวัตถุทุกชนิด มิฉะนั้นคุณอาจประสบปัญหาการสุ่มขัดข้องเป็นต้น
Johan Karlsson

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"และ"key1"ด้วยNotification.Key.key0และ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
alpennec

ขอบคุณดูเหมือนว่าKeystruct ได้ถูกลบไปตั้งแต่นั้น ฉันกำลังปรับปรุงคำตอบ
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.