3

我无法使用 XIB 将属性注入到视图控制器中initWithNibName:bundle:

例子:

这是我的组装:

@implementation AppAssembly

- (ViewControllerC *)viewControllerC
{
    return [TyphoonDefinition withClass:[ViewControllerC class]
                          configuration:^(TyphoonDefinition *definition) {
      [definition injectProperty:@selector(name) with:@"Injected string"];
    }];
}

@end

ViewControllerA 代码:

@implementation ViewControllerA

- (IBAction)buttonAction:(id)sender 
{
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNibName:@"ViewControllerB" bundle:nil];
    [self.navigationController pushViewController:viewControllerB animated:YES];
}

@end

ViewControllerB 代码:

@implementation ViewControllerB

- (IBAction)buttonAction:(id)sender 
{
    ViewControllerC *viewControllerC = [[ViewControllerC alloc] initWithNibName:@"ViewControllerC" bundle:nil];
    [self.navigationController pushViewController:viewControllerC animated:YES];
}

@end

ViewControllerC 代码:

@interface ViewControllerC : UIViewController

@property (copy, nonatomic) NSString *name;

@end

@implementation ViewControllerC

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // Why is this not being injected?
    self.title = self.name;
}

@end

AppDelegate 代码:

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ViewControllerA *rootViewController = [[ViewControllerA alloc] initWithNibName:@"ViewControllerA" bundle:nil];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = navigationController;
    [self.window makeKeyAndVisible];

    return YES;
}

@end

我已经检查了样本,它们与这种方法不同。请你能告诉我我做错了什么吗?

谢谢。

4

2 回答 2

1

Typhoon 是一个依赖注入容器,这意味着它不会检测、调配或以其他方式触及您的类。因此,要获得注入依赖项的类的实例,我们必须询问 Typhoon。

为什么不用于情节提要?

当使用 plist 集成时,Typhoon 注册 TyphoonStoryboard 代替 UIStoryboard 以根据情节提要中的定义发出实例 - 就像普通情节提要一样,具有注入依赖项的额外好处。

在其他地方,为了获取注入依赖项的实例,我们使用程序集接口,并询问 Typhoon。

解决步骤:

在您的程序集中添加 ViewControllerB 的定义。(在 Objective-C 中,如果你愿意,你也可以使用自动注入宏)。

- (ViewControllerB *)viewControllerB
{
    return [TyphoonDefinition withClass:[ViewControllerB class] 
        configuration:^(TyphoonDefinition *definition) {

        [definition useInitializer:@selector(initWithNibName:bundle:) 
            parameters:^(TyphoonMethod *initializer) {

            [initializer injectParameterWith:@"ViewControllerB"];
            [initializer injectParameterWith:[NSBundle mainBundle]];
        }];

        [definition injectProperty:@selector(assembly) with:self];
    }];
}

向 ViewControllerB 添加一个属性:

//Start with this, next task is to back this with a protocol
@property(nonatomic, strong) AppAssembly *assembly;

现在更改实例化 ViewControllerC 的按钮操作:

ViewControllerC *viewControllerC = self.assembly.viewControllerC
[self.navigationController pushViewController:viewControllerC animated:YES];

现在我的应用程序类依赖于我的 TyphoonAssembly,如果我不想要这个怎么办?

所有 Typhoon 程序集都可以由协议支持,因此您的应用程序只能看到实例的提供者,而不是 Typhoon。如果您希望从 Typhoon 迁移,只需提供该协议的替代实现 - 您仍将拥有一个健壮的架构。

于 2015-07-20T01:47:45.413 回答
0

因此,我必须首先向我的 AppAssembly 询问一个带有注入程序集的 viewControllerB 实例,然后我才能使用它来获取 viewControllerC 的一个实例。

应用程序代码:

- (ViewControllerB *)viewControllerB
{
    return [TyphoonDefinition withClass:[ViewControllerB class]
                          configuration:^(TyphoonDefinition *definition) {
                              [definition useInitializer:@selector(initWithNibName:bundle:)
                                              parameters:^(TyphoonMethod *initializer) {
                                                  [initializer injectParameterWith:@"ViewControllerB"];
                                                  [initializer injectParameterWith:nil];
                                              }];

                              [definition injectProperty:@selector(assembly) with:self];
                          }];
}

- (ViewControllerC *)viewControllerC
{
    return [TyphoonDefinition withClass:[ViewControllerC class]
                          configuration:^(TyphoonDefinition *definition) {
                              [definition useInitializer:@selector(initWithNibName:bundle:)
                                              parameters:^(TyphoonMethod *initializer) {
                                                  [initializer injectParameterWith:@"ViewControllerC"];
                                                  [initializer injectParameterWith:nil];
                                              }];

                              [definition injectProperty:@selector(name) with:@"Injected string"];
    }];
}

ViewControllerA 代码:

@implementation ViewControllerA

- (IBAction)buttonAction:(id)sender
{
    ViewControllerB *viewControllerB = [[[AppAssembly new] activate] viewControllerB];
    [self.navigationController pushViewController:viewControllerB animated:YES];
}

@end

ViewControllerB 代码:

@implementation ViewControllerB

- (IBAction)buttonAction:(id)sender 
{
    ViewControllerC *viewControllerC = [self.assembly viewControllerC];
    [self.navigationController pushViewController:viewControllerC animated:YES];
}

@end

ViewControllerC 代码:

@implementation ViewControllerC

- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.title = self.name;
}

@end

如您所见,我必须这样做:ViewControllerB *viewControllerB = [[[AppAssembly new] activate] viewControllerB];不确定是否有其他方法。因为这样做,我能够将程序集注入 ViewControllerB,这让我可以这样做:ViewControllerC *viewControllerC = [self.assembly viewControllerC]; 但是,我注意到我也可以这样做ViewControllerC *viewControllerC = [[[AppAssembly new] activate] viewControllerC];,所以不确定哪种方法更好。无论如何,我想我必须调用 new 并至少激活一次。

谢谢。

于 2015-07-23T15:19:13.613 回答