NSNotificationCenter로 객체를 전달하는 방법


129

내 앱 대리자에서 다른 클래스의 알림 수신자로 객체를 전달하려고합니다.

integer 전달하고 싶습니다 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를 다른 클래스 에 전달하고 싶습니다 .


스위프트 2.0 및 스위프트 3.0 용 stackoverflow.com/questions/36910965/…
Sahil

답변:


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)];
Jon

notification.name을 왜 비교해야하는지 잘 모르겠습니다. addObserver ()를 수행 할 때 이름 맵핑이 수행되어야합니다. receiveTestNotification은 특정 알림을 관찰 할 때만 호출해야합니다.
Johan Karlsson

1
Johan,이 간단한 경우에 당신은 맞지만, 여러 개의 알림이 같은 핸들러를 트리거 할 수 있습니다
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

4
@Kairos는 이와 같이 사용하도록 설계되지 않았기 때문에. object의 param 인은 postNotificationName 이 알림을 보내 하나를 의미한다.
xi.lin

2
예, 객체는 userInfoparam을 사용하여 NSDictionary로 전달되어야하며 위의 허용 된 답변이이를 표시하도록 편집되었습니다.
David Douglas

1
이것은 매우 오해의 소지가 있습니다. 왜 그 대답에 많은 투표가 있습니까? 삭제해야합니다. 모든 사용자는이를 위해 정확하게 작성된 userInfo를 사용해야합니다.
Shinnyx

좋아, 피드백 주셔서 감사합니다 ... userInfo객체 데이터를 전달하는 방법으로 사전 을 사용하도록 답변을 업데이트했습니다 .
David Douglas

27

스위프트 2 버전

@Johan Karlsson이 지적했듯이 ... 잘못하고있었습니다. NSNotificationCenter와 정보를주고받는 올바른 방법은 다음과 같습니다.

먼저 postNotificationName의 초기화 프로그램을 살펴 봅니다.

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

출처

우리는 userInfo매개 변수를 사용하여 정보를 전달할 것 입니다. 이 [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 ()의 의도 된 사용을 위반하고 있습니다. 그러나 당신은 혼자가 아닙니다. 사용자 객체를 보내기 위해 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.key0Notification.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

감사합니다 Key. 그 이후 구조체가 제거 된 것 같습니다 . 나는 대답을 업데이트 중입니다
frouo

1

스위프트 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.