Accessing ViewController's method in custom Class - ios

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

Related

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.

iOS unable to remove Notification observer. Deinit not getting called

I have a UIView similar to the one you can see below:
class ViewTaskViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
subscribeToNotifications()
}
func subscribeToNotifications() {
let notification = NotificationCenter.default
notification.addObserver(forName: Notification.Name(rawValue: "TimerUpdated"), object: nil, queue: nil, using: handleUpdateTimer)
print("Subscribed to NotificationCenter in ViewTaskViewController")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("TUFU TUFU TUFU")
NotificationCenter.default.removeObserver(self)
}
deinit {
print("DENINT")
}
#objc func handleUpdateTimer(notification: Notification) {
if let userInfo = notification.userInfo, let timeInSeconds = userInfo["timeInSeconds"] as? Int {
withUnsafePointer(to: &self.view) {
print("We got timeeeeee \(timeInSeconds) \($0)")
}
//do something here....
}
}
}
The issue I am having is that I am unable to remove the observers from this particular UIView when the user hits the back button and returns to another viewController.
ViewWillDisppear is called but deinit is not called. The strange thing is that if we remove subscribeToNotifications() from viewDidLoad() then the deinit is called.
The other issue is related to a memory leak. As you can see in the screenshot below, when the view does subscribe to notifications and the user leaves/re-enters the view, the memory usage increase.
Now compare that to when the subscribeToNotifications() is commented out, there is no increase in memory usage and only one instance of the viewController.
The conclusion is that there seems to be a correlation between the notification subscription creation of a new instance of the UIView hence the deinit is not being called.
I'd like to find out if there is a way we can deinitialize the view and unsubscribe from the notification.
Please let me know if you need further information. :)
I've found the removeObserver() only works if you use this version of addObserver()
notification.addObserver(self, selector:#selector(self.handleUpdateTimer), name: Notification.Name(rawValue: "TimerUpdated"), object: nil)
I'm guessing with the original version you aren't actually indicating who the observer is.
As #Spads said you can use
NotificationCenter.default.addObserver(self, selector: #selector(subscribeToNotifications), name: NSNotification.Name(rawValue: "TimerUpdate"), object: nil)
or the one you already have.
you can remove your notification by it's name or it's reference
NotificationCenter.default.removeObserver(self, name: "TimerUpdate", object: nil)
if you declared your notification at the top of your class then you can directly pass the reference of your notification to be removed in your case notification
NotificationCenter.default.removeObserver(notification)
You should store your newly added observer in a opaque object (NSObjectProtocol) and then call NotificationCenter.default.removeObserver(self.nameOfObserver)

NotificationCenter not receiving posts

I have a class that accepts accelerometer data and posts it in a notification like so:
func notify(accel: accelPoint){
NotificationCenter.default.post(name: Notification.Name("newRawData"), object: nil)
}
And two objects set up to observe this, the first being a viewController:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(FirstViewController.newRawData), name: Notification.Name("newRawData"), object: nil)
Which calls the function:
func newRawData(notification: NSNotification){ ...
This works just fine.
The other observer is in a regular Swift class, instantiated in the app delegate. (I have tried doing this before and after creating the notifying class):
init(){
NotificationCenter.default.addObserver(self, selector: #selector(FilterManager.newRawData), name: Notification.Name("newRawData"), object: nil)
}
Which should call the function below but for some reason it does not.
#objc func newRawData(){
print("WHYYY")
}
The name this class is correct, and I have seen the the observer is being registered and the notifications are being posted so why isn't this class being notified like the other?
Also, why do I have to expose the newRawData function in the second class to objective-C but not the newRawData in the viewController class?
did you referenced FilterManager class in your AppDelegate? if not add this code in you AppDelegate class. also you can make FilterManger singleton to solve this problem.
var filterManger = FilterManager()

AVSpeechSynthsesizer on timer

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.

fatal error on calling function from another class

I'm having trouble on calling the function from a different class. I have this:
class ViewController: UIViewController {
func addToOrder(orderNumber:String) {
orderCount.text = orderNumber
}
}
Now in my other class:
class TableViewController: UITableViewController {
func addToOrder(button: UIButton) {
ViewController().addToOrder("100")
//I also tried
var menu = ViewController()
menu.addToOrder("100")
}
}
I'm getting error on this line
orderCount.text = orderNumber
with this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
You can use NSNotificationCenter for that.
Follow this step:
first of all add this in your first viewController where you want to update text:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshTable:", name: "refresh", object: nil)
}
Which will add an observer when your load your first view and also add this helper method which will call when you come back to this view:
func refreshTable(notification: NSNotification) {
let orderDetail = NSUserDefaults.standardUserDefaults().integerForKey("order") //this will read your integer which you will save on second view.
orderCount.text = "\(orderDetail)"
}
In your next view add this code when you are coming back to previous view.
#IBAction func goBack(sender: AnyObject) {
//store your int here
NSUserDefaults.standardUserDefaults().setInteger(100, forKey: "order")
//send notification to first view.
NSNotificationCenter.defaultCenter().postNotificationName("refresh", object: nil, userInfo: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
Hope this will help.
It's orderCount (which probably is a UILabel) which is nil at initialization-time. If this is a IBOutlet created in a storyboard, you will need to store your text as a separate property, and set the text of your Label to this property in your ´viewDidLoad´ method

Resources