11

I am working on a test project in Swift 3. I am trying to pass textField string from one class to another class using NotificationCenter. I am trying to workout the answer from this link: pass NSString variable to other class with NSNotification and how to pass multiple values with a notification in swift

I tried few answers from the above link but nothing worked.

My code:

//First VC

import UIKit


extension Notification.Name {        
public static let myNotificationKey = Notification.Name(rawValue: "myNotificationKey")    
}


class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


@IBAction func sendData(_ sender: AnyObject) {

    let userInfo = [ "text" : textView.text ]
    NotificationCenter.default.post(name: .myNotificationKey, object: nil, userInfo: userInfo)

}

}

//SecondVC

 import Foundation
 import  UIKit

 class viewTwo: UIViewController {

@IBOutlet weak var result: UILabel!



override func viewDidLoad() {


}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(self.notificationReceived(_:)), name: .myNotificationKey, object: nil)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: .myNotificationKey, object: nil)
}

func notificationReceived(_ notification: Notification) {
    guard let text = notification.userInfo?["text"] as? String else { return }
    print ("text: \(text)")

    result.text = text
}

enter image description here}

I am not sure whats wrong with the code. Above, code originally marked as a answered which, I found from the first link. Code been converted to Swift.

Community
  • 1
  • 1
Joe
  • 8,868
  • 8
  • 37
  • 59
  • duplicate of http://stackoverflow.com/questions/36910965/how-can-i-pass-received-data-through-nsnotificationcenter-in-my-swift-ios-app/36911168#36911168 – Sahil Oct 13 '16 at 08:41
  • Don't use object to pass data, it doesn't work this way. Have a look at the answer below. – alexburtnik Oct 13 '16 at 08:57

5 Answers5

34

Don't use object parameter to pass data. It is meant to filter notifications with the same name, but from a particular object. So if you pass some object when you post a notification and another object when you addObserver, you won't receive it. If you pass nil, you basically turn off this filter.

You should use userInfo parameter instead.

First, it is better to define notification's name as extension for Notification.Name. This approach is much safer and more readable:

extension Notification.Name {        
    public static let myNotificationKey = Notification.Name(rawValue: "myNotificationKey")    
}

Post notification:

let userInfo = [ "text" : text ]
NotificationCenter.default.post(name: .myNotificationKey, object: nil, userInfo: userInfo)

Subscribe:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(self.notificationReceived(_:)), name: .myNotificationKey, object: nil)
}

Unsubscribe:

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: .myNotificationKey, object: nil)
}

Method to be called:

func notificationReceived(_ notification: Notification) {
    guard let text = notification.userInfo?["text"] as? String else { return }
    print ("text: \(text)")
}
alexburtnik
  • 7,661
  • 4
  • 32
  • 70
  • http://stackoverflow.com/questions/36910965/how-can-i-pass-received-data-through-nsnotificationcenter-in-my-swift-ios-app/36911168#36911168 – Sahil Oct 13 '16 at 08:46
  • @alex I just updated the code from your answer.Still, i am not getting any result. can you please take a look at the update....thanks – Joe Oct 13 '16 at 09:15
  • You missed `(_:)` at the end of your selector – alexburtnik Oct 13 '16 at 09:18
  • @Joe I've update the answer with more details on how to define notificationName. Also note that you must removeObserver at some point. – alexburtnik Oct 13 '16 at 09:30
  • @alex I implemented your updated answer.still nothing happening. i don't know what am i missing.I wondering am i need import any delegate etc....thanks – Joe Oct 13 '16 at 09:55
  • Hmm, can you please update your question with exact code, that you have, so I can find the mistake? I've just tried it in a test project and it works as expected. – alexburtnik Oct 13 '16 at 09:58
  • Oh, I think I see your problem. Are you sure that second controller is already created when you post notification from the first one? If it's not, he cannot listen to the posted notification in the past. Check this with two breakpoints: `addObserver` must be called before `postNotification` obviously. – alexburtnik Oct 13 '16 at 10:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/125581/discussion-between-alex-and-joe). – alexburtnik Oct 13 '16 at 10:21
8

Pass text using userInfo which is a optional Dictionary of type [AnyHashable:Any]? in Swift 3.0 and it is [NSObject : AnyObject]? in swift 2.0

@IBAction func sendData(_ sender: UIButton) {

// post a notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: ["text": textValue.text])

print(textValue) // textValue printing

}

in viewDidLoad

// Register to receive notification

NotificationCenter.default.addObserver(self, selector: #selector(self. incomingNotification(_:)), name:  NSNotification.Name(rawValue: "notificationName"), object: nil)

and in incomingNotification

func incomingNotification(_ notification: Notification) {
if let text = notification.userInfo?["text"] as? String {
   print(text)
  // do something with your text   
}


}
Sahil
  • 9,096
  • 3
  • 25
  • 29
2

In your sendData method pass textField.text into Notification object and in your incomingNotification do this:

guard let theString = notification.object as? String else {
    print("something went wrong")
    return 
}

resultLabel.text = theString

You can also use blocks to pass data between controllers.

Maksym Musiienko
  • 1,248
  • 8
  • 16
  • 1
    I would add a log message in the if statement. This way you find a potential error earlier. – dasdom Oct 13 '16 at 08:37
  • @MaksymMusiienko I just updated the code from your answer.Still, i am not getting any result. can you please take a look at the update....thanks – Joe Oct 13 '16 at 08:48
  • 1
    @MaksymMusiienko Your answer is misleading, `object` property should not be used like that. – alexburtnik Oct 13 '16 at 08:59
  • change your `addObserver` method to `NotificationCenter.default.addObserver(self, selector: #selector(self.incomingNotification(_:)), name: NSNotification.Name(rawValue: "NOTIFICATION_NAME"), object: nil)`. Also, try to use self-explanatory names for notifications. And another and **right way** to pass data is using userInfo. – Maksym Musiienko Oct 13 '16 at 09:01
1

Use dispatchQueue because your notification is posting before your view load. Therefore just give delay in your notification Post.

@IBAction func sendData(_ sender: AnyObject) {

    let userInfo = [ "text" : textView.text ]
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
 NotificationCenter.default.post(name: .myNotificationKey, object: nil, userInfo: userInfo)        }

}
adiga
  • 34,372
  • 9
  • 61
  • 83
0

Just use NotificationCenter to send and receive the notification that state changed. Pass the data through some a data model such as an ObservableObject (particularly if you're bridging between SwiftUI and UIKit). Here's are a couple of extension that make it pretty simple for lightweight inter-component signaling without the cumbersome forgettable semantics of NotificationCenter. (Of course you define your own Notification.Name constants to be meaningful to your purpose).

extension Notification.Name {
    static let startEditingTitle = Notification.Name("startEditingTitle")
    static let stopEditingTitle  = Notification.Name("stopEditingTitle")
}

extension NotificationCenter {
    static func wait(_ name : Notification.Name) async {
        for await _ in NotificationCenter.default.notifications(named: name) {
            break;
        }
    }
    static func post(_ name : Notification.Name) {
        NotificationCenter.default.post(name: name, object: nil)
    }
    @discardableResult static func postProcessing(_ name: Notification.Name, using block: @escaping (Notification) -> Void) -> NSObjectProtocol {
        NotificationCenter.default.addObserver(forName: name, object: nil, queue: OperationQueue.main, using: block)
    }
}

To post a notification is as simple as:

  NotificationCenter.post(.startEditingTitle)

And to receive the notification elsewhere:

  NotificationCenter.postProcessing(.startEditingTitle) (_ in {
      print("Started editing title")
  }

Or to just wait for the notification instead of asynchronously handling it:

  NotificationCenter.wait(.startEditingTitle)
clearlight
  • 12,255
  • 11
  • 57
  • 75