在 application:DidFinishLaunchingWithOptions 中注入依赖项后,如何防止 ViewController 被释放:

How can I prevent ViewControllers from being deallocated after I inject them with a dependency in application:DidFinishLaunchingWithOptions:

我正在尝试从 AppDelegate 向我的选项卡式应用程序中的所有 viewController 注入依赖项(对数据存储),而不是通过返回到 appDelegate 来访问数据存储。我正在使用故事板。

我在 application:didFinishLaunchingWithOptions: 中执行此操作,代码执行无误。

但是,当出现任何 viewController 时,我注入数据存储的 属性 包含 nil。我期待它有对数据存储的引用。

我想也许我的数据存储在 application:didFinishLaunchingWithOptions returns 之后超出范围并导致数据存储变为零。但据我所知,ARC 应该可以防止这种情况发生。

我开始怀疑 VC 可能会在 application:didFinishLaunchingWithOptions 之后消失:完成 运行。所以我向视图控制器添加了一个 dealloc 方法,看看它是否被调用,瞧瞧,它确实被调用了。这就解释了为什么我之前注入的依赖不再存在。

现在我卡住了,因为我不知道如何将依赖项注入视图控制器。我剩下的唯一想法是向我的 AppDelegate 添加属性并使用它们来保留视图控制器,但这感觉有点危险,因为我现在正在干扰视图控制器的 iOS 管理。

这是 AppDelegate 中的代码:

//AppDelegate.h
#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

//AppDelegate.m
#import "AppDelegate.h"
#import "InjectedViewController.h"
#import "InjectedDataStore.h"
@interface AppDelegate ()
@property (strong, nonatomic) InjectedDataStore *myDataStore;
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

UIStoryboard *storyBoard;
storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *initViewController = [storyBoard instantiateInitialViewController];
[self.window setRootViewController:initViewController];


if (!_myDataStore) {
    self.myDataStore = [[InjectedDataStore alloc]init];
    NSLog(@"alloc inited %@", self.myDataStore);
}

UITabBarController *tabBarController = (UITabBarController *)initViewController;
    for (InjectedViewController *ivc in tabBarController.viewControllers) {
        ivc.dataStore = self.myDataStore;
        NSLog(@"dataStore injected into ivc: %@", ivc.dataStore);
    }

NSLog(@"application:didFinishLaunching... done");

return YES;
}

@end

这是我的视图控制器子class,其中包含我要注入的 属性:

//InjectedViewController.h

#import <UIKit/UIKit.h>
#import "InjectedDataStore.h"

NS_ASSUME_NONNULL_BEGIN

@interface InjectedViewController : UIViewController
@property (strong, nonatomic) InjectedDataStore *dataStore;
@end

NS_ASSUME_NONNULL_END

InjectedViewController.m 是样板文件,否则为空。 InjectedDataStore.m 和 .h 是样板 Cocoa Touch class 没有任何属性或方法。

这是其中一个视图控制器 - 它嵌入在选项卡视图中。 (另一个选项卡的另一个视图控制器是相同的。

//FirstViewController.h
#import <UIKit/UIKit.h> 
#import "InjectedViewController.h"
@interface FirstViewController : InjectedViewController
@end

//FirstViewController.m
#import "FirstViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"data store for FirstVC: %@", self.dataStore);
}

- (void) dealloc {
NSLog(@"First VC dealloc called");
}
@end

最后,控制台输出:

alloc inited <InjectedDataStore: 0x600001d483a0> 
dataStore injected into ivc: <InjectedDataStore: 0x600001d483a0> 
dataStore injected into ivc: <InjectedDataStore: 0x600001d483a0>
application:didFinishLaunching... done

First VC dealloc called   ///this is what causes the injected element to disappear.
Second VC dealloc called  ///causes the injected element to disappear.

data store for FirstVC: (null) 
data store for SecondVC: (null)

(我最终会实施一个协议,但现在因为我一直坚持让注射工作,所以我没有考虑它。)

在我看来,我在这里所做的与@juanignaciosi 对 this 问题的回答非常相似:

感谢任何反馈,我是 iOS 的新手。

你的 window 属性 是 nil。 由于 iOS 13 系统正在使用来自场景委托的 window 属性。 如果不需要,只需从 plist 中删除场景委托和 UIApplicationSceneManifest