iOS:循环依赖于彼此之间的调用方法

use*_*482 1 objective-c circular-dependency ios

我正在尝试在我AppDelegate和我之间实现循环依赖,ViewController以从我AppDelegate到我调用方法,ViewController但是它不起作用。

请参阅我的代码,如下所示:

AppDelegate.h:

@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong,nonatomic) ViewController *mainView;

@end;
Run Code Online (Sandbox Code Playgroud)

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    [self.mainView doSomething];
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

ViewController.h:

#import <UIKit/UIKit.h>

@class AppDelegate;

@interface ViewController : UIViewController
@property (strong,nonatomic) AppDelegate *delegate;

-(void)doSomething;

@end;
Run Code Online (Sandbox Code Playgroud)

ViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.delegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
}

- (void)doSomething
{
    NSLog(@"doing something");
}
Run Code Online (Sandbox Code Playgroud)

我没有任何错误或警告,但doSomething从未调用过该方法。你们谁都知道为什么或我做错了什么?

非常感谢您的帮助。

mat*_*att 8

这与循环依赖无关。

如您所知,doSomething永远不会调用该方法,因为您在说

[self.mainView doSomething];
Run Code Online (Sandbox Code Playgroud)

...在self.mainView从未被赋予价值的时候。仅声明财产

@property (strong,nonatomic) ViewController *mainView;
Run Code Online (Sandbox Code Playgroud)

...不会将变量指向mainView实际的 ViewController实例;它是nil,并且一条消息不会nil产生任何错误,也不会导致任何事情发生。

可以通过在代码中添加一行来让ViewController设置对自身的引用来解决此问题:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.delegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
    self.delegate.mainView = self; // <--
}
Run Code Online (Sandbox Code Playgroud)

但是不要!一个简单的事实是,您的整个方法都是错误的。在您的应用程序委托中,无需保留对ViewController的引用。您的应用随时都有一个视图控制器层次结构。应用程序委托应该知道ViewController在该层次结构中的位置。

当出现链接消息时,我们在您的应用程序委托中:

- (BOOL)application:(UIApplication *)app
        openURL:(NSURL *)url
        options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
Run Code Online (Sandbox Code Playgroud)

那时,应用程序委托人的工作是知道 ViewController在视图控制器层次结构中的位置,甚至安排视图控制器层次结构,以便响应链接消息,显示ViewController的场景是否还存在。

如何执行取决于视图控制器层次结构的结构。您从层次结构的顶部开始,对于应用程序委托,层次结构的顶部是[[self window] rootViewController],然后一直向下移动到要与之对话的现有视图控制器。

您尚未告诉我们您的视图控制器层次结构,因此无法提供详细帮助。但是,例如,假设您的应用围绕导航控制器界面旋转。然后,对于应用程序委托,[[self window] rootViewController]是导航控制器,因此可以将其强制转换为该类:(UINavigationController*)[[self window] rootViewController]。然后,如果ViewController是导航控制器的根视图控制器,viewControllers[0]则将其拿到,然后根据需要再次进行投射:

UINavigationController* nav = (UINavigationController*)[[self window] rootViewController];
ViewController* vc = (ViewController*)nav.viewControllers[0];
Run Code Online (Sandbox Code Playgroud)

现在您可以将doSomething消息发送到vc。但这仅是一个例子。具体的细节取决于ViewController层次结构中ViewController的实际位置。当然,您可能还想弹出视图控制器,以便实际上显示 ViewController的场景,因为您可能无法保证在出现链接消息时就显示了它。

处理这种情况的另一种完全不同的方法是使用NSNotificationCenter 发布 ViewController实例已为其注册的通知。当您不完全知道视图控制器在视图控制器层次结构中的什么位置时,通常这是一种解决方案。但是在这种情况下,您应该知道这一点。