How to call method in view controller in app delegate?
if its the root its easy:
(window.rootViewController as? ViewController)?.myFunction()
if its on top of a navigationController
((window.rootViewController as? UINavigationController)?.topViewController as? ViewController)?.myFunction()
But in either case its weird and probably not the right thing to do. Use NotificationCenter instead and post a notification name in your AppDelegate and then have the ViewController listen for messages and respond accordingly.
how to call a method in a view controller from Appdelegate in Swift?
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()
}
How to call custom methods in AppDelegate whenever any view controller is appear or disappears
Instead of overriding UIViewController (which would mandate that all your view controllers must inherit from it, and thus introduces tight coupling) instead you can create an extension for UIViewController and swizzle viewWillAppear and viewWillDisappear.
This link has all the details and code required to swizzle a UIViewController in Swift
http://nshipster.com/method-swizzling/
It provides the code to swizzle viewWillAppear.You would call your app delegate method in the xxx_viewWillAppear method.
Calling UIViewController method from app delegate
- Notification. But you don't want this.
- You can get the reference to your that
viewController
in theAppDelegate
. Than call that(void)goToBeginning
method in the(void)applicationDidEnterBackground
For example: In your ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
}
And in your AppDelegate
:
@class MyViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (weak, nonatomic) MyViewController *myViewController;
@end
And in the AppDelegate
's implementation:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.myViewController goToBeginning];
}
How to call viewController's method in appdelegate
This may help you (tested in Swift 4)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(applicationDidBecomeActive),
name: Notification.Name.UIApplicationDidBecomeActive,
object: nil)
}
}
@objc func applicationDidBecomeActive() {
print("UIApplicationDidBecomeActive")
}
Note: Don't forget to remove observer when your view controller is no longer in use/memory (as this is an application level observer and will be called every time your application becomes active, whether your view controller is active or not.
Here is code to remove observer:
NotificationCenter.default.removeObserver(self,
name: Notification.Name.UIApplicationDidBecomeActive,
object: nil)
want to call ViewController's method from appdelegate
While this has been correctly answered for the case where the view controller is the rootViewController
, for completeness sake here's how you can get this to work with any view controller:
// ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
- (void)myMethod;
@end
// ViewController.m
#import "ViewController.h"
#import "AppDelegate.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
}
- (void)myMethod
{
NSLog(@"Doing something interesting");
}
// AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (weak, nonatomic) ViewController *myViewController;
@end
// AppDelegate.m
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self.myViewController myMethod];
}
Call a method from AppDelegate - Objective-C
Background information (class definition vs class instance)
The important concept here is the difference between a class definition and a class instance.
The class definition is the source code for the class. For example ViewController.m
contains the definition for the myViewController
class, and AppDelegate.m
contains the definition for the AppDelegate
class. The other class mentioned in your question is UIApplication
. That is a system-defined class, i.e. you don't have the source code for that class.
A class instance is a chunk of memory on the heap, and a pointer to that memory. A class instance is typically created with a line of code like this
myClass *foo = [[myClass alloc] init];
Note that alloc
reserves space on the heap for the class, and then init
sets the initial values for the variables/properties of the class. A pointer to the instance is then stored in foo
.
When your application starts, the following sequence of events occurs (roughly speaking):
- the system creates an instance of the UIApplication class
- the pointer to the UIApplication instance is stored somewhere in a
system variable - the system creates an instance of the AppDelegate class
- the pointer to the AppDelegate is stored in a variable called
delegate
in the UIApplication instance - the system creates an instance of the MyViewController class
- the pointer to the MyViewController class is stored somewhere
The storage of the pointer to MyViewController is where things get messy. The AppDelegate class has a UIWindow property called window
. (You can see that in AppDelegate.h.) If the app only has one view controller, then the pointer to that view controller is stored in the window.rootViewController
property. But if the app has multiple view controllers (under a UINavigationController or a UITabBarController) then things get complicated.
The spaghetti code solution
So the issue that you face is this: when the system calls the applicationDidEnterBackground
method, how do you get the pointer to the view controller? Well, technically, the app delegate has a pointer to the view controller somewhere under the window
property, but there's no easy way to get that pointer (assuming the app has more than one view controller).
The other thread suggested a spaghetti code approach to the problem. (Note that the spaghetti code approach was suggested only because the OP in that other thread didn't want to do things correctly with notifications.) Here's how the spaghetti code works
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
This code retrieves the pointer to the UIApplication instance that the system created, and then queries the delegate
property to get a pointer to the AppDelegate instance. The pointer to self
, which is a pointer to the MyViewController instance, is then stored in a property in the AppDelegate.
The pointer to the MyViewController instance can then be used when the system calls applicationDidEnterBackground
.
The correct solution
The correct solution is to use notifications (as in kkumpavat's answer)
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
- (void)didEnterBackground
{
NSLog( @"Entering background now" );
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
With notifications, you aren't storing redundant pointers to your view controllers, and you don't have to figure out where the system has stored the pointer to your view controller. By calling addObserver
for the UIApplicationDidEnterBackgroundNotification
you're telling the system to call the view controller's didEnterBackground
method directly.
Related Topics
How to Rotate an Uiimageview by 20 Degrees
Nsurlsession "Http Load Failed Kcfstreamerrordomainssl, -9813 ; Self Signing Certificate
How Does One Print All Wkwebview on and Offscreen Content Osx and iOS
Using Custom Fonts in Interface Builder
iOS Provisioning and Certifcates - Will Revoke/Renew Effect App Store Apps
Adding Glow Effect to Uibutton - iOS
Sudzc Arc Version - Objc_Msgsend Call Causes Exc_Bad_Access Using 64-Bit Architecture
How to Cache Videos? iOS - Swift
How to Set an Title of the Currently Playing Audio in iPhone Lock Screen
Nsstring Containsstring Crashes
Swift - Uiimagepickercontroller - How to Use It
iOS 13 - How to Login in In-App Purchase Sandbox Account
Libmobilegestalt Mobilegestaltsupport.M:153 Mobilegestalt.C:550 Xcode Console
Remembering Scroll Position on Uitableview