AVSpeechSynthsesizer on timer - ios

If a switch is turned on, text-to-word spoken every x seconds. The switch is on the first view controller, and the speech occurs after a segue to the second view controller.
Code in the first view controller:
#IBAction func speakwords(sender: AnyObject) {
NSNotificationCenter.defaultCenter().postNotificationName("speaknotif", object: speakwords)
Code in the second view controller:
verride func viewDidLoad() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("talk:"), name: "speaknotif", object: self.view.window)
func talk(notification: NSNotification){guard let count = notification.object else {return}
if Bool(TYPE_BOOL as! NSO) = "true"{
let speechsynth = AVSpeechSynthesizer()}

In your case, Notification Center was useless. Because you are calling post method before adding observer for that notification. So notification concept won't work there.
Instead of this, just set one Bool like "isSwitchSelected". And pass that value to next vc, check if the value is yes, then call func talk method.

Related

Accessing ViewController's method in custom Class

I have made a func in ViewController, that can receive a string and change the title of a label, that is located on screen.
Here it is:
func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
What i want to do, is to call this function (viewController's method?) from another class.
Like that:
class MainLabelEditor{
func updateLabelOnScreen{
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")
}
}
Unfortunately, it doesn't work.
Here is what xcode says:
If I press return, it shows this:
The question is, how do i call setNewTitleForMainLabelOnScreen from MainLabelEditor?
I usually use NotificationCenter to deliver data from other ViewController.
ViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(setNewTitleForMainLabelOnScreen), name: NSNotification.Name(rawValue: "changeTitle"), object: nil)
}
#objc func setNewTitleForMainLabelOnScreen(_ notification: Notification){
mainLabelOnScreen.cell?.title = notification.object as! String
}
: Specifies the value passed to NotificationCenter object as title.
Other UIViewController
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "changeTitle"), object: "titleTextValue")
: You can add the string value you want as the title to the object.
You can try:
public class func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
So it turns out, all you need to do is to type
ViewController().setNewTitleForMainLabelOnScreen(text: "Hello")
instead of
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")

Function returning emptying String when using Notification and observers?

In the following code I want to return a string from first controller to third controller. But it returns an empty string, when trying by notification and observers.
First View Controller
override function ViewDidLoad(){
NotificationCenter.default.addObserver(self, selector:
#selector(token(notification:)), name: .token, object: nil)
}
#objc func token (notification:Notification) -> String!{
return self.token! //return token
}
extension Notification.Name {
static let token = Notification.Name("Token")
}
ThirdViewController*
override function ViewDidLoad(){
let token = NotificationCenter.default.post(name: .token, object: nil)
print(token) // () printing empty
}
If I understood you problem correctly you want to pass object from first controller to third, you can use segue for it. This is the example how you can pass it to second, the same thing to pass forward from second to third
#IBAction func goForawrd(_ sender: UIButton) {
performSegue(withIdentifier: "second", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "second" {
let vc = segue.destination as? SecondViewController
vc?.object = yourObjectYouWantToPass
}
}
or if you don't want to use segue you can use next code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewController(withIdentifier: "second")
secondVC.object = yourObjectYouWantToPass
don't forget to set viewController identifier before
This
NotificationCenter.default.post(name: .token, object: nil) doesn't return anything you get the observer wrongly it posts the notification and if there is an observer it'll be forwarded to it , so this flow occurs
1-
NotificationCenter.default.post(name: .token, object: nil)
2-
NotificationCenter.default.addObserver(self, selector:
#selector(token(notification:)), name: .token, object: nil
3-
#objc func token (notification:Notification) {}
if you need to send data from first to second set it when you segue/present/push , if you need to send data from second to first use a delegate
Okay so you are printing nil since that is not the value of the token just the reference for the post method.
Since it is not a bidirectional thing you cannot retrieve the value there.
If you want to achieve this by notifications these are the required steps:
Send a notification about you need a token
When notification arrived on first controller grab what you need and send another notification with the value you need, and handle it where you need.
First View Controller
override function ViewDidLoad(){
NotificationCenter.default.addObserver(self, selector:
#selector(token(notification:)), name: .tokenGet, object: nil)
}
#objc func token (notification:Notification) {
NotificationCenter.default.post(name: .tokenSet, object: token)
}
extension Notification.Name {
static let tokenGet = Notification.Name("TokenGet")
static let tokenSet = Notification.Name("TokenSet")
}
ThirdViewController*
override function ViewDidLoad(){
NotificationCenter.default.addObserver(self, selector:
#selector(token(notification:)), name: .tokenSet, object: nil)
NotificationCenter.default.post(name: .tokenGet, object: nil)
}
func tokenSet(notification: Notification) {
/// here you can get the value from notification
}
Note that i would NOT do in this way. Pass the token through the view controllers or create a class which is responsible for token handling and pass that around.

App Delegate : Service call coming back from background

I want to call a web service whenever application coming back in the foreground. I am calling it from didBecomeActive().
What's the best way to handle it and pass data to Root view controller?
Since the data you want to pass is always going to the same view controller you should instead set the observer in that view controller instead of app delegate. This way you won't need to pass any data in the first place.
class YourViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default
.addObserver(self, selector: #selector(activityHandler(_:)),
name: UIApplication.didBecomeActiveNotification, object: nil)
}
#objc func activityHandler(_ notification: Notification) {
//Call your web service here
}
}
You have two choices. Get rootViewController and pass the data, handle it.
func applicationDidBecomeActive(_ application: UIApplication) {
// 1
let rootVC1 = self.window?.rootViewController
// 2
let rooVC2 = application.windows.first?.rootViewController
...
/*
pass data to rootVC1 or rootVC2
*/
}

Pass data from one view controller to the other using unwind segue with identifier

Here is my code:
I am making the user to be able to select image from phone and then want to jump back to the previous view controller passing this image file too..
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
if (segue.identifier == "unwindToThis") {
}
}
If your original view controller is still loaded in memory you can use an NSNotification via NSNotificationCenter.
In the view controller that needs the data, in viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "imageReceived:", name: "imageReceived", object: self.videoDeviceInput?.device)
Then add the deinit method to the same controller, this will remove the observer when the view controller is no longer loaded.
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self, name: "imageReceived", object: nil)
}
Still in the same class create a method to handle the notification:
func imageReceived(notification: NSNotification) {
if let image = notification.object as? UIImage {
// Do your image stuff here.
}
}
In the view controller where you create or get the data you need to pass back you can to trigger the notification with the data like so:
NSNotificationCenter.defaultCenter().postNotificationName("imageReceived", object: yourUIImage)

Triggering a specific action when the app enters foreground from a local notification in iOS? (using swift)

I am building an iOS app using the new language Swift. Now it is an HTML5 app, that displays HTML content using the UIWebView. The app has local notifications, and what i want to do is trigger a specific javascript method in the UIWebView when the app enters foreground by clicking (touching) the local notification.
I have had a look at this question, but it does not seem to solve my problem. I have also come across this question which tells me about using UIApplicationState, which is good as that would help me know the the app enters foreground from a notification. But when the app resumes and how do i invoke a method in the viewController of the view that gets displayed when the app resumes?
What i would like to do is get an instance of my ViewController and set a property in it to true. Something as follows
class FirstViewController: UIViewController,UIWebViewDelegate {
var execute:Bool = false;
#IBOutlet var tasksView: UIWebView!
}
And in my AppDelegate i have the method
func applicationWillEnterForeground(application: UIApplication!) {
let viewController = self.window!.rootViewController;
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("FirstView") as FirstViewController
setViewController.execute = true;
}
so what i would like to do is when the app enters foreground again, i want to look at the execute variable and run the method as follows,
if execute{
tasksView.stringByEvaluatingJavaScriptFromString("document.getElementById('sample').click()");
}
Where should i put the code for the logic to trigger the javascript from the webview? would it be on viewDidLoad method, or one of the webView delegate methods? i have tried to put that code in the viewDidLoad method but the value of the boolean execute is set to its initial value and not the value set in the delegate when the app enters foreground.
If I want a view controller to be notified when the app is brought back to the foreground, I might just register for the UIApplication.willEnterForegroundNotification notification (bypassing the app delegate method entirely):
class ViewController: UIViewController {
private var observer: NSObjectProtocol?
override func viewDidLoad() {
super.viewDidLoad()
observer = NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [unowned self] notification in
// do whatever you want when the app is brought back to the foreground
}
}
deinit {
if let observer = observer {
NotificationCenter.default.removeObserver(observer)
}
}
}
Note, in the completion closure, I include [unowned self] to avoid strong reference cycle that prevents the view controller from being deallocated if you happen to reference self inside the block (which you presumably will need to do if you're going to be updating a class variable or do practically anything interesting).
Also note that I remove the observer even though a casual reading of the removeObserver documentation might lead one to conclude is unnecessary:
If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method.
But, when using this block-based rendition, you really do need to remove the notification center observer. As the documentation for addObserver(forName:object:queue:using:) says:
To unregister observations, you pass the object returned by this method to removeObserver(_:). You must invoke removeObserver(_:) or removeObserver(_:name:object:) before any object specified by addObserver(forName:object:queue:using:) is deallocated.
I like to use the Publisher initializer of NotificationCenter. Using that you can subscribe to any NSNotification using Combine.
import UIKit
import Combine
class MyFunkyViewController: UIViewController {
/// The cancel bag containing all the subscriptions.
private var cancelBag: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
addSubscribers()
}
/// Adds all the subscribers.
private func addSubscribers() {
NotificationCenter
.Publisher(center: .default,
name: UIApplication.willEnterForegroundNotification)
.sink { [weak self] _ in
self?.doSomething()
}
.store(in: &cancelBag)
}
/// Called when entering foreground.
private func doSomething() {
print("Hello foreground!")
}
}
Add Below Code in ViewController
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector:#selector(appMovedToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func appMovedToForeground() {
print("App moved to foreground!")
}
In Swift 3, it replaces and generates the following.
override func viewDidLoad() {
super.viewDidLoad()
foregroundNotification = NotificationCenter.default.addObserver(forName:
NSNotification.Name.UIApplicationWillEnterForeground, object: nil, queue: OperationQueue.main) {
[unowned self] notification in
// do whatever you want when the app is brought back to the foreground
}

Resources