简体   繁体   中英

how to call a method in a view controller from Appdelegate in Swift?

在此处输入图像描述

this Main Menu VC will be opened when the app launched for the first time or after the user back to the app (the app become active after enter the background state).

every time this main menu VC is opened, ideally I need to update the time that the date time data comes from the server. in this main menu vc class I call getDateTimeFromServer() after that I updateUI() .

but to update the data after the app enter the background and back to the foreground, the getDateTimeFromServer() and updateUI() shall be activated from Appdelegate using function.

func applicationWillEnterForeground(application: UIApplication) {

    }

so how do I activate a method that are exist in Main Menu VC from AppDelegate

You don't need to call the view controller method in app delegate. Observe foreground event in your controller and call your method from there itself.

Observe for the UIApplicationWillEnterForeground notification in your viewController viewDidLoad:

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.yourMethod), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)

Implement this to receive callback when user enters foreground

@objc func yourMethod() {
     // Call getDateTimeFromServer()
}

You can do something like that, using a technique called Key-Value Observation :

class CommonObservableData: NSObject {
    // Use @objc and dynamic to ensure enabling Key-Value Observation
    @objc dynamic var dateTime: Date?

    static let shared = CommonObservableData()

    func updateFromWeb() {
        // callWebThen is a function you will define that calls your Web API, then
        // calls a completion handler you define, passing new value to your handler
        callWeb(then: { self.dateTime = $0 })
    }
}

Then you observe on it using Swift 4 's new NSKeyValueObservation .

class SomeViewController: UIViewController {
    var kvo: NSKeyValueObservation?
    func viewDidLoad() {
        ...
        kvo = CommonObservableData.shared.observe(
            \CommonObservableData.dateTime, { model, change in

            self.label.text = "\(model.dateTime)"

        })
    }
}

Key-Value Observation is originally an Objective-C technique that is "somewhat revived" by Swift 4, this technique allows you to observe changes on a property (called a Key in Objective-C) of any object.

So, in the previous code snippets, we made a class, and made it a singleton, this singleton has an observable property called dateTime , where we could observe on change of this property, and make any change in this property automatically calls a method where we could update the UI.

Read about KVO here:

Key-Value Observation Apple Programming Guide

Key-Value Observation using Swift 4

Also, if you like Rx and RFP (Reactive Functional Programming), you can use RxSwift and do the observation in a cleaner way using it.

These types of messaging are in most cases done with static context. As it was already mentioned you could alternatively use notification center within the within the view controller to be notified of your application entering foreground. I discourage you creating custom notifications for this though (but is a possible solution as well).

Anyway for your specific case I suggest you have a model that contains your data. Then create a shared instance of it.

class MyDataModel {

   static var shared: MyDataModel = {
        let model = MyDataModel()
        model.reloadData()
        return model
   }()

   var myObjects: [MyObject]?

   func reloadData() {
       // load data asynchronously
   }
}

Now when your view controller needs to reload it simply uses MyDataModel.shared.myObjects as data source.

In app delegate all you do is reload it when app comes back to foreground using MyDataModel.shared.reloadData() .

So now a delegate is still missing so we add

protocol MyDataModelDelegate: class {
    func myDataModel(_ sender: MyDataModel, updatedObjects objects: [MyObject]?)
}
class MyDataModel {

    weak var delegate: MyDataModelDelegate?

   static var shared: MyDataModel = {

Now when your view controller appears it needs to assign itself as a delegate MyDataModel.shared.delegate = self . And implement the protocol in which a reload on the view must be made.

A callout to the delegate can simply be done in a model setter:

}()

var myObjects: [MyObject]? {
   didSet {
       delegate.myDataModel(self, updatedObjects: myObjects)
   }
}

func reloadData() {

In swift 4 and 5, the notification name is changed the below code working for both.

    notifyCenter.addObserver(self, selector: #selector(new), name:UIApplication.willEnterForegroundNotification, object: nil)

 @objc func  new(){}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM