在我的ViewController.m中
-(void)viewDidLoad { [super viewDidLoad]; AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; appDelegate.myViewController = self; }
在我的AppDelegate中:
@class MyViewController; @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (weak,nonatomic) MyViewController *myViewController; @end
在AppDelegate的实现中:
- (void)applicationDidEnterBackground:(UIApplication *)application { [self.myViewController method]; }
所以我把这个代码放在我的项目中,它工作正常,但我不明白代码如何工作,一行一行. sharedApplication有什么作用?为什么我必须设置一个委托而不是只创建一个ViewController实例,如:
ViewController * instance = [[ViewController alloc] init]; [instance method];
解决方法
这里重要的概念是类定义和类实例之间的区别.
类定义是类的源代码.例如,ViewController.m包含myViewController类的定义,AppDelegate.m包含AppDelegate类的定义.你问题中提到的另一个类是UIApplication.这是一个系统定义的类,即您没有该类的源代码.
类实例是堆上的一块内存,以及指向该内存的指针.通常使用这样的代码行创建类实例
myClass *foo = [[myClass alloc] init];
请注意,alloc为类的堆保留空间,然后init设置类的变量/属性的初始值.然后将指向实例的指针存储在foo中.
当您的应用程序启动时,会发生以下事件序列(粗略地说):
>系统创建UIApplication类的实例
>指向UIApplication实例的指针存储在某个地方
系统变量
>系统创建AppDelegate类的实例
>指向AppDelegate的指针存储在一个名为的变量中
在UIApplication实例中委托
>系统创建MyViewController类的实例
>指向MyViewController类的指针存储在某处
存储指向MyViewController的指针是事情变得混乱的地方. AppDelegate类有一个名为window的UIWindow属性. (您可以在AppDelegate.h中看到.)如果应用程序只有一个视图控制器,则指向该视图控制器的指针存储在window.rootViewController属性中.但是如果应用程序有多个视图控制器(在UINavigationController或UITabBarController下),那么事情会变得复杂.
所以你面临的问题是:当系统调用applicationDidEnterBackground方法时,你如何获得指向视图控制器的指针?好吧,从技术上讲,app委托在窗口属性下的某个地方有一个指向视图控制器的指针,但是没有简单的方法来获取该指针(假设该应用程序有多个视图控制器).
另一个线程建议使用意大利面条代码来解决问题. (请注意,建议使用意大利面条代码方法只是因为其他线程中的OP不希望正确处理通知.)以下是意大利面条代码的工作原理
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; appDelegate.myViewController = self;
此代码检索指向系统创建的UIApplication实例的指针,然后查询delegate属性以获取指向AppDelegate实例的指针.然后,指向self的指针(它是指向MyViewController实例的指针)存储在AppDelegate的属性中.
然后,当系统调用applicationDidEnterBackground时,可以使用指向MyViewController实例的指针.
正确的解决方案
- (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]; }
通过通知,您不会将冗余指针存储到视图控制器,也不必确定系统将指针存储到视图控制器的位置.通过为UIApplicationDidEnterBackgroundNotification调用addObserver,您告诉系统直接调用视图控制器的didEnterBackground方法.