'NotificationCenter to pass data in Swift

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.



Solution 1:[1]

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)")
}

Solution 2:[2]

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   
}


}

Solution 3:[3]

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.

Solution 4:[4]

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)        }

}

Solution 5:[5]

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)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 adiga
Solution 5 clearlight