appsquickly / typhoon

Powerful dependency injection for Objective-C ✨✨ (https://PILGRIM.PH is the pure Swift successor to Typhoon!!)✨✨
https://pilgrim.ph
Apache License 2.0
2.7k stars 269 forks source link

InjectedClass property is nil #555

Closed ghost closed 7 years ago

ghost commented 7 years ago

Hello, I have several assemblies:

screen shot 2017-04-06 at 16 38 02

One of them work fine, other return nil property when I inject it. Here is example of assembly:

@implementation MTHCacheAssembly

- (MTHParticipantsStringGenerator *)participantsStringGenerator {
    return [TyphoonDefinition withClass:[MTHParticipantsStringGenerator class]
                          configuration:^(TyphoonDefinition *definition) {
                              definition.scope = TyphoonScopeLazySingleton;
                          }];
}

@end

And here is example of property injection:

#import "TyphoonAutoInjection.h"

@interface MTHSmartNamesLabel ()

@property (strong, nonatomic) InjectedClass(MTHParticipantsStringGenerator) participantsStringGenerator;

@end

@implementation MTHSmartNamesLabel

- (id)doSomething {
   return [self.participantsStringGenerator ...];
}

@end

When I use participantsStringGenerator - it isn't initialized. I use the same way of injection with different assemblies and they work fine. I will be very grateful for the help.

alexgarbarev commented 7 years ago

@rmnbozhchenko how do you create your MTHSmartNamesLabel instance? From Typhoon or just new?

alexgarbarev commented 7 years ago

Try this category for NSObject to instantiate objects using default factory


#import <Typhoon/TyphoonDefinition.h>
#import "NSObject+TyphoonDefaultFactory.h"
#import "TyphoonComponentFactory.h"
#import "TyphoonComponentFactory+InstanceBuilder.h"
#import "Typhoon+Infrastructure.h"

@implementation NSObject (TyphoonDefaultFactory)

+ (BOOL)isAutoDefinition:(TyphoonDefinition *)definition
{
    NSString *key = [definition key];
    return [key hasPrefix:[NSString stringWithFormat:@"%@_", [self class]]];
}

+ (instancetype)newUsingTyphoon
{
    id result = nil;

    TyphoonComponentFactory *defaultFactory = [TyphoonComponentFactory factoryForResolvingUI];
    if (defaultFactory) {
        NSArray *definitions = [defaultFactory allDefinitionsForType:[self class]];

        if (definitions.count == 1 && [self isAutoDefinition:definitions.firstObject]) {
            definitions = @[];
        }

        switch (definitions.count) {
            case 0:
                result = [self new];
                [defaultFactory inject:result];
                break;
            case 1:
                result = [defaultFactory componentForType:[self class]];
                break;
            default:
                result = [self new];
                DDLogWarn(@"Found more than one definition for class: %@", self);
                break;
        }
    }

    return result;
}

- (void)injectUsingTyphoon
{
    TyphoonComponentFactory *defaultFactory = [TyphoonComponentFactory factoryForResolvingUI];
    [defaultFactory inject:self];
}

+ (instancetype)fromTyphoon
{
    TyphoonComponentFactory *factory = [TyphoonComponentFactory factoryForResolvingUI];
    return [factory componentForType:self];
}

@end

Then

MTHSmartNamesLabel *label = [MTHSmartNamesLabel newUsingTyphoon];
[label doSomething];
ghost commented 7 years ago

Yes, in my case Label initialize from storyboard. Thank you for advice, I will try it!

ghost commented 7 years ago

Thank you for advice, I override initWithCoder and use injectUsingTyphoon. Now it works! I am very grateful for the help!