Reuse assembly in other assemblies

63 Views Asked by At

I'm trying to integrate typhoon into my project.

I have three classes, DBManager, ProductDataManager, and CustomerDataManager. Both ProductDataManager and CustomerDataManager depend on DBManager for db operation.

@interface ProductDataManager ()
@property (nonatomic, strong) DBManager *dbManager;
@end

@implementation ProductDataManager

- (instancetype)initWithDBManager:(DBManager*)dbManager
{
    self = [super init];
    if (self) {
        _dbManager = dbManager;
    }
    return self;
}


@interface CustomerDataManager ()
@property (nonatomic, strong) DBManager *dbManager;
@end

@implementation CustomerDataManager

- (instancetype)initWithDBManager:(DBManager*)dbManager
{
    self = [super init];
    if (self) {
        _dbManager = dbManager;
    }
    return self;
}

Now I create three assemblies for them.

@interface DBManagerAssembly ()

@end

@implementation DBManagerAssembly

- (DBManager *)dbManager {
    return [TyphoonDefinition withClass:[DBManager class] configuration:^(TyphoonDefinition *definition) {
        }];
        definition.scope = TyphoonScopeSingleton;
    }];
}






@interface CustomerDataManagerAssembly ()
@property (nonatomic, strong) DBManagerAssembly *dbManagerAssembly;
@end

@implementation CustomerDataManagerAssembly

- (CustomerDataManager *)customerDataManager {
    return [TyphoonDefinition withClass:[CustomerDataManager class] configuration:^(TyphoonDefinition *definition) {
        [definition useInitializer:@selector(initWithDBManager:) parameters:^(TyphoonMethod *initializer) {
            [initializer injectParameterWith:self.dbManager];
        }];
    }];
}

- (DBManager *)dbManager {
    return [self.dbManagerAssembly dbManager];
}





@interface ProductDataManagerAssembly ()
@property (nonatomic, strong) DBManagerAssembly *dbManagerAssembly;
@end

@implementation ProductDataManagerAssembly

- (ProductDataManager *)productDataManager {
    return [TyphoonDefinition withClass:[ProductDataManager class] configuration:^(TyphoonDefinition *definition) {
        [definition useInitializer:@selector(initWithDBManager:) parameters:^(TyphoonMethod *initializer) {
            [initializer injectParameterWith:self.dbManager];
        }];
    }];
}

- (DBManager *)dbManager {
    return [self.dbManagerAssembly dbManager];
}

Activate them in AppDelegate

- (NSArray *)initialAssemblies
{
    return @[[DBManagerAssembly class], [ProductDataManagerAssembly class], [CustomerDataManagerAssembly class]];
}

But on app startup, it throws an exception

[NSException raise:NSInvalidArgumentException format:@"Key '%@' is already registered.", _definition.key];

My question is... how to reuse assembly properly and avoid exception?

1

There are 1 best solutions below

2
Jasper Blues On BEST ANSWER

Typhoon allows you to create logical groupings of the key architectural actors in your system. This feature is called Assembly Modularization. All of the components defined go into a single TyphoonComponentFactory - which contains recipes for emitting built instances.

assembly modules

Before activation the assembly returns definitions. At runtime you can use the assembly as a facade to return built instances. It uses Objective-C message forwarding to resolve method calls to [factory componentForKey:theMethodName]. Therefore:

  • Each component in the entire set of assemblies must have a unique name.

In your code, you've defined:

- (DBManager *)dbManager {
    return [self.dbManagerAssembly dbManager];
}

Remove this definition, and edit customerDataManager to instead have:

[initializer injectParameterWith:[self.dbManagerAssembly dbManager]];

All will be well.