如何防止ViewControllers在注入application:DidFinishLaunchingWithOptions中的依赖关系后被deallocated。

问题描述 投票:0回答:1

我试图从AppDelegate中向我的标签式应用中的所有ViewControllers注入一个依赖关系(到数据存储),而不是通过回到appDelegate中访问数据存储。我使用的是一个故事板。

我在application:didFinishLaunchingWithOptions:中这样做,代码执行起来没有错误。

然而,当任何一个viewControllers呈现时,我注入数据存储的属性包含nil。我希望它能有一个对数据存储的引用。

我想也许我的数据存储在application:didFinishLaunchingWithOptions返回后超出了范围,导致数据存储变成了nil。但据我所知,ARC应该可以防止这种情况发生。

我开始怀疑,也许在application:didFinishLaunchingWithOptions:完成运行后,VC可能会消失。所以我给视图控制器添加了一个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

这是我的视图控制器子类,里面有我想注入的属性。

//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类,没有任何属性或方法。

而这里是其中一个视图控制器--它被嵌入到一个标签视图中。另一个标签页的视图控制器是相同的。

//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的回答非常相似。这个 问题。

感谢任何反馈,我对iOS是个相对新手。

ios objective-c dependency-injection uiviewcontroller appdelegate
1个回答
1
投票

你的窗口属性是 nil.由于iOS 13系统采用的是 window 从场景委托人中删除场景委托人和 UIApplicationSceneManifest 如果你不需要,可以从plist中获取。

© www.soinside.com 2019 - 2024. All rights reserved.