在 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
。
我正在尝试从 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
。