[英]Call a method from AppDelegate - Objective-C
我試圖從applicationDidEnterBackground
方法中的AppDelegate.m
調用我的ViewController.m
的現有方法,所以我找到了這個鏈接: 從app delegate調用UIViewController方法 ,它告訴我實現這段代碼:
在我的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
。
當您的應用程序啟動時,會發生以下事件序列(粗略地說):
delegate
的變量中 存儲指向MyViewController的指針是事情變得混亂的地方。 AppDelegate類有一個名為window
的UIWindow屬性。 (您可以在AppDelegate.h中看到。)如果應用程序只有一個視圖控制器,那么指向該視圖控制器的指針將存儲在window.rootViewController
屬性中。 但是如果應用程序有多個視圖控制器(在UINavigationController或UITabBarController下),那么事情會變得復雜。
意大利面條代碼解決方案
所以你面臨的問題是:當系統調用applicationDidEnterBackground
方法時,你如何獲得指向視圖控制器的指針? 好吧,從技術上講,app委托在window
屬性下的某個地方有一個指向視圖控制器的指針,但是沒有簡單的方法來獲取該指針(假設該應用程序有多個視圖控制器)。
另一個線程建議使用意大利面條代碼來解決問題。 (請注意,建議使用意大利面條代碼方法只是因為其他線程中的OP不希望正確處理通知。)以下是意大利面條代碼的工作原理
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.myViewController = self;
此代碼檢索指向系統創建的UIApplication實例的指針,然后查詢delegate
屬性以獲取指向AppDelegate實例的指針。 然后,指向self
的指針(它是指向MyViewController實例的指針)存儲在AppDelegate的屬性中。
然后,當系統調用applicationDidEnterBackground
時,可以使用指向MyViewController實例的指針。
正確的解決方案
正確的解決方案是使用通知(如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];
}
通過通知,您不會將冗余指針存儲到視圖控制器,也不必確定系統將指針存儲到視圖控制器的位置。 通過調用addObserver
for UIApplicationDidEnterBackgroundNotification
你告訴系統直接調用視圖控制器的didEnterBackground
方法。
你有兩個問題。
1) sharedApplication
什么作用?
[UIApplication sharedApplication]
為您提供屬於您的應用程序的UIApplication實例。 這是您App的集中控制點。 有關更多信息,您可以在iOS開發人員站點上閱讀UIApplication類參考 。
2)為什么我必須設置委托而不是僅僅創建ViewController的實例?
使用alloc
/ init
再次在AppDelegate
創建控制器將創建新實例,並且此新實例不會指向您所指的控制器。 所以你不會得到你想要的結果。
但是在applicationDidEnterBackground
這個特定用例中,您不需要在AppDelegate
引用您的控制器。 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];
}
視圖控制器已經被實例化為NIB /故事板過程的一部分,因此如果您的應用程序委托執行自己的alloc
/ init
,您只需創建另一個實例(與創建NIB /故事板的實例無關)。
您概述的構造的目的僅僅是為應用程序委托對NIB /故事板為您實例化的視圖控制器的引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.