[英]Call a method from AppDelegate - Objective-C
I was trying to call an existing method of my ViewController.m
from AppDelegate.m
inside the applicationDidEnterBackground
method, so I found this link: Calling UIViewController method from app delegate , which told me to implement this code: 我试图从
applicationDidEnterBackground
方法中的AppDelegate.m
调用我的ViewController.m
的现有方法,所以我找到了这个链接: 从app delegate调用UIViewController方法 ,它告诉我实现这段代码:
In my ViewController.m 在我的ViewController.m中
-(void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
}
In my AppDelegate: 在我的AppDelegate中:
@class MyViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (weak, nonatomic) MyViewController *myViewController;
@end
And in the AppDelegate's implementation: 在AppDelegate的实现中:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.myViewController method];
}
So I put this code in my project and it worked fine, but I didn't understand how the code works, line by line. 所以我把这个代码放在我的项目中,它工作得很好,但我不明白代码如何工作,一行一行。 What does the
sharedApplication
do? sharedApplication
什么作用? Why must I set a delegate instead of just creating an instance of ViewController, like: 为什么我必须设置一个委托而不是只创建一个ViewController实例,如:
ViewController * instance = [[ViewController alloc] init];
[instance method];
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. 例如,
ViewController.m
包含myViewController
类的定义, AppDelegate.m
包含AppDelegate
类的定义。 The other class mentioned in your question is UIApplication
. 你问题中提到的另一个类是
UIApplication
。 That is a system-defined class, ie 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. 请注意,
alloc
为类的堆保留空间,然后init
设置类的变量/属性的初始值。 A pointer to the instance is then stored in foo
. 然后将指向实例的指针存储在
foo
。
When your application starts, the following sequence of events occurs (roughly speaking): 当您的应用程序启动时,会发生以下事件序列(粗略地说):
delegate
in the UIApplication instance delegate
的变量中 The storage of the pointer to MyViewController is where things get messy. 存储指向MyViewController的指针是事情变得混乱的地方。 The AppDelegate class has a UIWindow property called
window
. AppDelegate类有一个名为
window
的UIWindow属性。 (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. (您可以在AppDelegate.h中看到。)如果应用程序只有一个视图控制器,那么指向该视图控制器的指针将存储在
window.rootViewController
属性中。 But if the app has multiple view controllers (under a UINavigationController or a UITabBarController) then things get complicated. 但是如果应用程序有多个视图控制器(在UINavigationController或UITabBarController下),那么事情会变得复杂。
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? 所以你面临的问题是:当系统调用
applicationDidEnterBackground
方法时,你如何获得指向视图控制器的指针? 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). 好吧,从技术上讲,app委托在
window
属性下的某个地方有一个指向视图控制器的指针,但是没有简单的方法来获取该指针(假设该应用程序有多个视图控制器)。
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
(请注意,建议使用意大利面条代码方法只是因为其他线程中的OP不希望正确处理通知。)以下是意大利面条代码的工作原理
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. 此代码检索指向系统创建的UIApplication实例的指针,然后查询
delegate
属性以获取指向AppDelegate实例的指针。 The pointer to self
, which is a pointer to the MyViewController instance, is then stored in a property in the AppDelegate. 然后,指向
self
的指针(它是指向MyViewController实例的指针)存储在AppDelegate的属性中。
The pointer to the MyViewController instance can then be used when the system calls applicationDidEnterBackground
. 然后,当系统调用
applicationDidEnterBackground
时,可以使用指向MyViewController实例的指针。
The correct solution 正确的解决方案
The correct solution is to use notifications (as in kkumpavat's answer) 正确的解决方案是使用通知(如kkumpavat的答案)
- (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. 通过调用
addObserver
for UIApplicationDidEnterBackgroundNotification
你告诉系统直接调用视图控制器的didEnterBackground
方法。
You have two question here. 你有两个问题。
1) What does the sharedApplication
do? 1)
sharedApplication
什么作用?
The [UIApplication sharedApplication]
gives you UIApplication instance belongs to your application. [UIApplication sharedApplication]
为您提供属于您的应用程序的UIApplication实例。 This is centralised point of control for you App. 这是您App的集中控制点。 For more information you can read UIApplication class reference on iOS developer site.
有关更多信息,您可以在iOS开发人员站点上阅读UIApplication类参考 。
2) Why must I set a delegate instead of just creating an instance of ViewController? 2)为什么我必须设置委托而不是仅仅创建ViewController的实例?
Creating controller in AppDelegate
again using alloc
/ init
will create new instance and this new instance does not point to the controller you are referring to. 使用
alloc
/ init
再次在AppDelegate
创建控制器将创建新实例,并且此新实例不会指向您所指的控制器。 So you will not get result you are looking for. 所以你不会得到你想要的结果。
However in this particular use case of applicationDidEnterBackground
, you don't need to have reference of you controller in AppDelegate
. 但是在
applicationDidEnterBackground
这个特定用例中,您不需要在AppDelegate
引用您的控制器。 You ViewController can register for UIApplicationDidEnterBackgroundNotification
notification in viewDidLoad
function and unregister in dealloc
function. ViewController可以在
viewDidLoad
函数中注册UIApplicationDidEnterBackgroundNotification
通知,并在dealloc
函数中取消注册。
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod) name:UIApplicationDidEnterBackgroundNotification object:nil];
//Your implementation
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
The view controller is already instantiated as part of the NIB/storyboard process, so if your app delegate does its own alloc
/ init
, you are simply creating another instance (which bears no relation to the one created the NIB/storyboard). 视图控制器已经被实例化为NIB /故事板过程的一部分,因此如果您的应用程序委托执行自己的
alloc
/ init
,您只需创建另一个实例(与创建NIB /故事板的实例无关)。
The purpose of the construct you outline is merely to give the app delegate a reference to the view controller that the NIB/storyboard instantiated for you. 您概述的构造的目的仅仅是为应用程序委托对NIB /故事板为您实例化的视图控制器的引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.