簡體   English   中英

從AppDelegate調用方法 - Objective-C

[英]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

當您的應用程序啟動時,會發生以下事件序列(粗略地說):

  • 系統創建UIApplication類的實例
  • 指向UIApplication實例的指針存儲在系統變量的某個位置
  • 系統創建AppDelegate類的實例
  • 指向AppDelegate的指針存儲在UIApplication實例中名為delegate的變量中
  • 系統創建MyViewController類的實例
  • 指向MyViewController類的指針存儲在某處

存儲指向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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM