detect up volume change swift - ios

I'm having problems detecting when someone presses up or down volume button. For the moment I just play a file but I want to know when the user presses the button to show an alert when the volume changes. I'm developing in Swift and I'm using AVFoundation to create this player. For the moment I can't find something that works in Swift. I'm very new to this language.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var backgroundMusicPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
playBackgroundMusic("IronBacon.mp3")
}
func playBackgroundMusic(filename:String){
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
print(url)
guard let newUrl = url else{
print("couldn't find file: \(filename)")
return
}
do{
backgroundMusicPlayer = try AVAudioPlayer(contentsOfURL: newUrl)
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
}catch let error as NSError{
print(error.description)
}
}
#IBAction func playPauseAction(sender: UIButton) {
sender.selected = !sender.selected
if sender.selected {
backgroundMusicPlayer.play()
} else {
backgroundMusicPlayer.pause()
}
}
func ShowAlert(title: String, message: String, dismiss: String) {
let alertController = UIAlertController(title: title, message:
message, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: dismiss, style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}
func volumeUp(){
ShowAlert( "example", message: "example", dismiss: "close")
}
func volumeDown(){
ShowAlert( "example", message: "example", dismiss: "close")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

This should do the trick.
class ViewController: UIViewController {
// MARK: Properties
let notificationCenter = NSNotificationCenter.defaultCenter()
// MARK: Lifecycle
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
notificationCenter.addObserver(self,
selector: #selector(systemVolumeDidChange),
name: "AVSystemController_SystemVolumeDidChangeNotification",
object: nil
)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
notificationCenter.removeObserver(self)
}
// MARK: AVSystemPlayer - Notifications
func systemVolumeDidChange(notification: NSNotification) {
print(notification.userInfo?["AVSystemController_AudioVolumeNotificationParameter"] as? Float)
}
}

For some reason, the accepted answer does not work. Here is how you can do it in latest iOS versions -
func addObserver() {
NotificationCenter.default.addObserver(self,
selector: #selector(systemVolumeDidChange),
name: Notification.Name("SystemVolumeDidChange"),
object: nil)
}
func systemVolumeDidChange(notification: NSNotification) {
Log.msg("New Volume = \(notification.userInfo?["Volume"] as? Float)")
}
There are a few more fields in user info that can determine the volume change reason etc.

Related

How to change language (localisation) within the app in swift 5?

I am trying to localise iOS app which is developed in Swift 5. I have done with all localisation things in code as well as in storyboard. But I am not sure how to change language within the app when i click on Language Button.
Is this possible to change app language within app? if yes How?
Please suggest best possible way to do same
I just did a similar implementation. Glad you asked and I saw this. Here is my implementation. You can modify.
enum Language: String, CaseIterable {
case english, german
var code: String {
switch self {
case .english: return "en"
case .german: return "de"
}
}
static var selected: Language {
set {
UserDefaults.standard.set([newValue.code], forKey: "AppleLanguages")
UserDefaults.standard.set(newValue.rawValue, forKey: "language")
}
get {
return Language(rawValue: UserDefaults.standard.string(forKey: "language") ?? "") ?? .english
}
}
static func switchLanguageBetweenEnglishAndGerman() {
selected = selected == .english ? .german : .english
}
}
Now you just need to call Language.selected == .german and reload the views.
To change localization throughout the app. For that, You need to follow the below step.
Create a Parent class of every UIViewController and define setupLocasitation method for further usage.
ParentViewController.swift
class ParentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func setupLocasitation(){
}
}
All other class of UIViewController should be a subclass of ParentViewController and override setupLocasitation method
ViewController1.swift
class ViewController1: ParentViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupLocasitation()
}
override func setupLocasitation() {
super.setupLocasitation()
print("Your localisation specifi code here...")
}
}
ViewController2.swift
class ViewController2: ParentViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupLocasitation()
}
override func setupLocasitation() {
super.setupLocasitation()
print("Your localisation specifi code here...")
}
}
ChangeLanguageVC.swift
You need to grab all instances of ParentViewController and force-fully call the setupLocasitation method.
class ChangeLanguageVC: ParentViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupLocasitation()
}
#IBAction func btnChangeLanguageTap(){
//Code for your language changes here...
let viewControllers = self.navigationController?.viewControllers ?? []
for vc in viewControllers{
if let parent = vc as? ParentViewController{
parent.setupLocasitation()
}
}
}
}
//
// LanguageExtensions.swift
// Flourish
//
// Created by Janko on 11/11/2020.
//
import Foundation
import UIKit
let languageKey = "languageKey"
var language : Int {
switch UserDefaults.standard.string(forKey: languageKey) {
case "en":
return 0
case "dutch":
return 1
default:
return 0
}
}
extension String {
func localizedLanguage()->String?{
var defaultLanguage = "en"
if let selectedLanguage = UserDefaults.standard.string(forKey: languageKey){
defaultLanguage = selectedLanguage
}
return NSLocalizedString(self, tableName: defaultLanguage, comment: "")
}
}
class LanguageLabel: UILabel{
required init?(coder: NSCoder) {
super.init(coder: coder)
NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: AppNotification.changeLanguage, object: nil)
}
#IBInspectable var localizedLanguage: String? {
didSet{
updateUI()
}
}
#objc func updateUI(){
if let string = localizedLanguage {
text = string.localizedLanguage()
}
}
}
class LanguageButton: UIButton{
required init?(coder: NSCoder) {
super.init(coder: coder)
NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: AppNotification.changeLanguage, object: nil)
}
#IBInspectable var localizedLanguage: String? {
didSet{
updateUI()
}
}
#objc func updateUI(){
if let string = localizedLanguage {
setTitle(string.localizedLanguage(), for: .normal)
}
}
}
struct AppNotification{
static let changeLanguage = Notification.Name("changeLanguage")
}
extension UIViewController{
func changeLanguage(){
let alert = UIAlertController(title: "Change Language", message: "Change it", preferredStyle: .alert)
let actionEnglish = UIAlertAction(title: "English", style: .default) { (action) in
UserDefaults.standard.setValue("en", forKey: languageKey)
NotificationCenter.default.post(name: AppNotification.changeLanguage , object: nil)
}
let actionMontenegrin = UIAlertAction(title: "Montenegrinish", style: .default) { (action) in
UserDefaults.standard.setValue("dutch", forKey: languageKey)
NotificationCenter.default.post(name: AppNotification.changeLanguage , object: nil)
}
alert.addAction(actionEnglish)
alert.addAction(actionMontenegrin)
present(alert, animated: true, completion: nil)
}
}

Why are the results of PDFKit .beginFindStrings nil?

Self-teaching novice here.
My end goal:
iOS/Mac app that loads a directory of PDFs, searches each for an array of strings, and lists which PDFs contain which strings where.
Problem in prototyping for only one PDF:
I receive a perplexing nil from loading a chosen PDF, running .beginFindStrings(["and", "the"], withOptions: .caseInsensitive) and waiting for the Notification .PDFDocumentDidEndFind to check [PDFSelection] .
That shouldn't be. Memory shows the PDF is loaded. Am I doing something wrong with threads? I think I've followed the async advice here: PDFKit background search
Code
import UIKit
import MobileCoreServices
import PDFKit
class ViewController: UIViewController, UIDocumentPickerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
var matchesFound: PDFSelection?
#IBOutlet weak var resultsLabel: UILabel!
#IBAction func importPDF(_ sender: Any) {
let picker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
picker.delegate = self
picker.allowsMultipleSelection = false
self.present(picker, animated: true)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else {return}
let data = try! Data(contentsOf: urls[0])
let subjectPDF = PDFDocument.init(data: data)
guard subjectPDF!.isLocked == false else {return}
subjectPDF!.beginFindStrings(["the", "and"], withOptions: .caseInsensitive)
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
}
#objc func onDidFindMatch(_ notification: Notification) {
resultsLabel.text = "\(String(describing: matchesFound?.string))"
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
}
Code with Markup
import UIKit
import MobileCoreServices
import PDFKit
class ViewController: UIViewController, UIDocumentPickerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
//Array of PDFSelection search results
var matchesFound: PDFSelection?
//Temporary display for search result strings
#IBOutlet weak var resultsLabel: UILabel!
//Choose a PDF to import, temporarily limited to one
#IBAction func importPDF(_ sender: Any) {
let picker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
picker.delegate = self
picker.allowsMultipleSelection = false
self.present(picker, animated: true)
}
//Load the picked PDF as subjectPDF, if unlocked
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else {return}
let data = try! Data(contentsOf: urls[0])
let subjectPDF = PDFDocument.init(data: data)
guard subjectPDF!.isLocked == false else {return}
//Find temporary array of strings
subjectPDF!.beginFindStrings(["the", "and"], withOptions: .caseInsensitive)
//Trigger results readout upon search competion
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
}
//Readout found strings to temporary label
#objc func onDidFindMatch(_ notification: Notification) {
resultsLabel.text = "\(String(describing: matchesFound?.string))"
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
}
The question was asked 7 months ago though, I hope you already found the solution.
Anyway the solution for your problem:
1- Move the line below to the viewDidLoad(), because you are adding an observer after triggering the beginFindString() method.
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
2- You are never assigning any value to matchesFound variable, so it's always nil.
3- To get the matches from beginFindString method, you need to add an observer for PDFDocumentDidFindMatch and get the data from userInfo instead of PDFDocumentDidEndFind.
PDFDocumentDidEndFind observer will be called when searching has been finished, you can use this observer for removing you loading view for instance.
Here is a sample code of the correct implementation:
var matchesFound = [PDFSelection]()
// MARK: Life cycle
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(didFindMatch(_:)), name: NSNotification.Name.PDFDocumentDidFindMatch, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// This method will get called every-time a match has been found.
#objc private func didFindMatch(_ sender: Notification) {
guard let selection = sender.userInfo?["PDFDocumentFoundSelection"] as? PDFSelection else { return }
self.matchesFound.append(selection)
}

Get selected text from custom UIMenuItem in WKWebView

I am creating an iOS app that has a custom UIMenuItem. This new custom UIMenuItem shows up when text is selected in WKWebView. How do I get the selected text.
I followed instructions in https://stackoverflow.com/a/49761522/6828076 to create a custom UIMenuItem. It works fine, but I need the selected text that was used when the custom UIMenuItem was tapped. There are many posts about using UIPasteboard but the custom item does not copy the selected text into the UIPasteboard, so I am unable to retrieve it.
func setupCustomMenu() {
let customMenuItem = UIMenuItem(title: "Foo", action:
#selector(ViewController.transelateMenuTapped))
UIMenuController.shared.menuItems = [customMenuItem]
UIMenuController.shared.update()
}
#objc func transelateMenuTapped() {
let yay = //Need to retrieve the selected text here
let alertView = UIAlertController(title: "Yay!!", message: yay, preferredStyle: .alert)
alertView.addAction(UIAlertAction(title: "cool", style: .default, handler: nil))
present(alertView, animated: true, completion: nil)
}
You can use Javascript for that.
Here's the code from the the answer you used, slightly altered to get the selected text by evaluating Javascript on the WKWebView:
import UIKit
import WebKit
class ViewController: UIViewController {
weak var webView: CustomMenuWebView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
prepareWebView()
}
#objc func translateMenuTapped(_ test: Any) {
webView.evaluateJavaScript("window.getSelection().toString()") { (test, error) in
guard let test = test as? String, error == nil else { return }
// ***** Here's the user's selected text *****
print(test)
}
}
}
private extension ViewController {
func prepareWebView() {
addWebViewToView()
loadWebViewContent()
setupCustomMenu()
}
func addWebViewToView() {
let webView = CustomMenuWebView(
frame: view.bounds, configuration: WKWebViewConfiguration())
view.addSubview(webView)
self.webView = webView
}
func loadWebViewContent() {
let url = URL(string: "https://www.google.com")
let request = URLRequest(url: url!)
webView.load(request)
}
func setupCustomMenu() {
let customMenuItem = UIMenuItem(
title: "Translate", action: #selector(ViewController.translateMenuTapped))
UIMenuController.shared.menuItems = [ customMenuItem ]
UIMenuController.shared.update()
}
}
class CustomMenuWebView: WKWebView {
// Turn off all other menu items
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}

ViewController loads but does not show

I'm using the Spotify iOS SDK. When a user logs into Spotify using the app, on call back loginVC transitions to musicPlayerVC. But, when a user logs into the app using a web view, once the web view dismisses and the loginVC is shown, the musicPlayerVC is loaded (print statements from viewDidLoad occur), but loginVC does not dismiss and musicPlayerVC does not show.
loginVC:
class loginVC: UIViewController, SPTStoreControllerDelegate, WebViewControllerDelegate {
#IBOutlet weak var statusLabel: UILabel!
var authViewController: UIViewController?
var firstLoad: Bool!
var Information: [String:String]?
override func viewDidLoad() {
super.viewDidLoad()
// NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
self.statusLabel.text = ""
self.firstLoad = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
let auth = SPTAuth.defaultInstance()
// Uncomment to turn off native/SSO/flip-flop login flow
//auth.allowNativeLogin = NO;
// Check if we have a token at all
if auth!.session == nil {
self.statusLabel.text = ""
return
}
// Check if it's still valid
if auth!.session.isValid() && self.firstLoad {
// It's still valid, show the player.
print("View did load, still valid, showing player")
self.showPlayer()
return
}
// Oh noes, the token has expired, if we have a token refresh service set up, we'll call tat one.
self.statusLabel.text = "Token expired."
if auth!.hasTokenRefreshService {
self.renewTokenAndShowPlayer()
return
}
// Else, just show login dialog
}
override var prefersStatusBarHidden: Bool {
return true
}
func getAuthViewController(withURL url: URL) -> UIViewController {
let webView = WebViewController(url: url)
webView.delegate = self
return UINavigationController(rootViewController: webView)
}
func sessionUpdatedNotification(_ notification: Notification) {
self.statusLabel.text = ""
let auth = SPTAuth.defaultInstance()
self.presentedViewController?.dismiss(animated: true, completion: { _ in })
if auth!.session != nil && auth!.session.isValid() {
self.statusLabel.text = ""
print("Session updated, showing player")
self.showPlayer()
}
else {
self.statusLabel.text = "Login failed."
print("*** Failed to log in")
}
}
func showPlayer() {
self.firstLoad = false
self.statusLabel.text = "Logged in."
self.Information?["SpotifyUsername"] = SPTAuth.defaultInstance().session.canonicalUsername
OperationQueue.main.addOperation {
[weak self] in
self?.performSegue(withIdentifier: "ShowPlayer", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowPlayer" {
if let destination = segue.destination as? PlayController {
destination.Information = self.Information
}
}
}
internal func productViewControllerDidFinish(_ viewController: SPTStoreViewController) {
self.statusLabel.text = "App Store Dismissed."
viewController.dismiss(animated: true, completion: { _ in })
}
func openLoginPage() {
self.statusLabel.text = "Logging in..."
let auth = SPTAuth.defaultInstance()
if SPTAuth.supportsApplicationAuthentication() {
self.open(url: auth!.spotifyAppAuthenticationURL())
} else {
self.authViewController = self.getAuthViewController(withURL: SPTAuth.defaultInstance().spotifyWebAuthenticationURL())
self.definesPresentationContext = true
self.present(self.authViewController!, animated: true, completion: { _ in })
}
}
func open(url: URL) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:],
completionHandler: {
(success) in
print("Open \(url): \(success)")
})
} else {
let success = UIApplication.shared.openURL(url)
print("Open \(url): \(success)")
}
}
func renewTokenAndShowPlayer() {
self.statusLabel.text = "Refreshing token..."
SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
SPTAuth.defaultInstance().session = session
if error != nil {
self.statusLabel.text = "Refreshing token failed."
print("*** Error renewing session: \(error)")
return
}
self.showPlayer()
}
}
func webViewControllerDidFinish(_ controller: WebViewController) {
// User tapped the close button. Treat as auth error
}
}
webController :
import UIKit
import WebKit
#objc protocol WebViewControllerDelegate {
func webViewControllerDidFinish(_ controller: WebViewController)
/*! #abstract Invoked when the initial URL load is complete.
#param success YES if loading completed successfully, NO if loading failed.
#discussion This method is invoked when SFSafariViewController completes the loading of the URL that you pass
to its initializer. It is not invoked for any subsequent page loads in the same SFSafariViewController instance.
*/
#objc optional func webViewController(_ controller: WebViewController, didCompleteInitialLoad didLoadSuccessfully: Bool)
}
class WebViewController: UIViewController, UIWebViewDelegate {
var loadComplete: Bool = false
var initialURL: URL!
var webView: UIWebView!
var delegate: WebViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
print(initialURL)
let initialRequest = URLRequest(url: self.initialURL)
self.webView = UIWebView(frame: self.view.bounds)
self.webView.delegate = self
self.webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.view.addSubview(self.webView)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.done))
self.webView.loadRequest(initialRequest)
}
func done() {
self.delegate?.webViewControllerDidFinish(self)
self.presentingViewController?.dismiss(animated: true, completion: { _ in })
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
if !self.loadComplete {
delegate?.webViewController?(self, didCompleteInitialLoad: true)
self.loadComplete = true
}
}
init(url URL: URL) {
super.init(nibName: nil, bundle: nil)
self.initialURL = URL as URL!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

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

Resources