smallseo.info

Typhoon

Poweful dependency injection for iOS & OSX (Objective-C & Swift) Typhoon - Powerful Dependency Injection for Objective-C & Swift typhoon - a new dependency injection container for objective-c

Swift: Cannot use library from Pod file

I'm using Typhoon library for Dependency Injection Framework. I use CocoaPod for installing this library. Here is my pod file:

target "typhoon-swift-demo" do
    pod 'Typhoon'
end

target "typhoon-swift-demoTests" do

end

I have installed successfully but when I open workspace project file. I type those line of code as Typhoon sample code:

public class ApplicationAssembly: TyphoonAssembly {

}

I meet error that my application doesn't recognize TyphoonAssembly I have tried to use some lines such as:

import Typhoon // not recogize typhoon
import TyphoonAssembly // not regconize

Please tell me how to fix this problem. What should I add before I can use library. Thanks :)


Source: (StackOverflow)

Typhoon Storyboard Integration

I am using a StoryBoard in my application. When I first started integrating Typhoon, I listed the Assemblies in the plist like so:

<key>TyphoonInitialAssemblies</key>
<array>
    <string>ApplicationAssembly</string>
    <string>CoreComponents</string>
</array>

This worked fine as I was injecting into the AppDelegate.

Now, if I need to inject into the various view controllers, it appears I have to remove the UILaunchStoryboardName and UIMainStoryboardFile from the application plist file, and use a TyphoonStoryboard like so:

- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    NSString *storyboardName = ...
    TyphoonComponentFactory *factory = ...

    TyphoonStoryboard *storyboard = [TyphoonStoryboard 
        storyboardWithName:storyboardName factory:factory bundle:nil];

    self.window = ...
    self.window.rootViewController = [storyboard instantiateInitialViewController];
    [self.window makeKeyAndVisible];

    return YES;
}

However, I'm confused where I obtain the TyphoonComponentFactory. Since I already list the assemblies in the plist, can I somehow use that?


Source: (StackOverflow)

Swift TyphoonBlockComponentFactory Error in XCTest

i’m using Swift with Typhoon and Cocoapods. Everything worked well until i started to write an Integrationtest (according to the Typhoon-Example-App Test) for my Typhoon component. I wanted to setup the TyphoonFactory in the Test setUp() method in the same way as i did in the AppDelegate. When i execute the test i always get a

TyphoonBlockComponentFactory assertIsAssembly:] + 244: ERROR: MyApp.MyAssembly is not a sub-class of TyphoonAssembly

error thrown by Typhoon (wich is using the kindOfClass method under the hood.) The same code is working perfectly in the AppDelegate and i can’t figure out whats wrong.

To verify this behavior i implemented the isKindOfClass check in booth classes (see code below):

  • AppDelegate -> true
  • MyComponentTest -> false

Can someone pls help me further? Thx a lot!

PodFile

inhibit_all_warnings!

target "MyApp" do
pod 'Typhoon', '2.1.0'
end

target "MyAppTests" do
pod 'Typhoon', '2.1.0'
end

MyAssembly.swift

public class MyAssembly : TyphoonAssembly{
    //Some definitions
}

AppDelegate.swift

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    …
    var assembly : MyAssembly = MyAssembly()
    //Always returns „true“
    println("Is type of class: \(assembly.isKindOfClass(TyphoonAssembly))")
    …
}

MyComponentTest.swift

import XCTest
import MyApp

class MyComponentTest: XCTestCase {

    override func setUp() {
        super.setup()
        var assembly : MyAssembly = MyAssembly()
        //Always returns „false“!
        println("Is type of class: \(assembly.isKindOfClass(TyphoonAssembly))")

        //Error is thrown „MyApp.MyAssembly is not a sub-class of TyphoonAssembly“
        var factory : TyphoonComponentFactory = TyphoonBlockComponentFactory(assembly: assembly) as TyphoonComponentFactory
    }
}

Source: (StackOverflow)

dyld_fatal_error with Typhoon+Swift+iOS7.x+Plist-bootstrapping

I have very annoying problem with Typhoon Framework version 2.3.0 in Swift project.

I included Typhoon in Podfile as mentiond in tutorial, installed Pods, created bridging header and added #import <Typhoon/Typhoon.h> in this header.

Then I created assembly subclass called ApplicationAssebly :

import Foundation

public class ApplicationAssembly: TyphoonAssembly {
    public dynamic func appDelegate() -> AnyObject {
        return TyphoonDefinition.withClass(AppDelegate.self) {
            (definition) in
            definition.injectProperty("myAssembly", with: self)
        }
    }
}

As you see I want to inject that assembly into AppDelegate. I have also added TyphoonInitialAssemblies entry in Info.plist file. And in this moment my problems has started. I have tested few combinations resulting in NSException :

Can't resolve assembly for name xxx

This combinations are (typhtest is project/bundle name):

  • ClassName in Info.plist: ApplicationAssembly, Defines Module property in Build Settings : No
  • ClassName in Info.plist: ApplicationAssembly, Defines Module property in Build Settings : Yes
  • ClassName in Info.plist: typhtest.ApplicationAssembly, Defines Module property in Build Settings : No
  • ClassName in Info.plist: typhtest.ApplicationAssembly, Defines Module property in Build Settings : Yes

I have found this answer on StackOverflow so I've tried the last combination :

  • ClassName in Info.plist: _TtC8typhtest19ApplicationAssembly, Defines Module property in Build Settings : Yes

This combination doesn't throw NSException but I have dyld_fatal_error, stack trace from iPhone 5s (iOS 7.1) below :

iPhone 5s - iOS 7.1 error stack trace

I get slightly different stack trace from iPhone simulator (iOS 7.1) :

iOS 7.1 emulator error stack trace

What is strange that it works on iOS 8.1 simulator ! Also Typhoon Sample Application for Swift works well on my device.

I also tried to clean any Xcode and project caches and DerivedData directories, I've cleaned project and build folder and rebuilded the project, but it's not working. My Xcode version is 6.1 (6A1052d) and I'm using OSX Yosemite 10.10.1 .

GitHub repository with my code : https://github.com/papcio28/Typhoon-Dyld-Error

Edited 21.11.2014

What is also strange is that if I create the factory manually and inject something also manually, Typhoon works. Steps that I've made are :

  1. Removed TyphoonInitialAssemblies item from Info.plist
  2. Changes AppDelegate.application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool to

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let factory = TyphoonBlockComponentFactory(assemblies: [AppAssembly()])
        factory.inject(self)
        return true
    }
    

But it doesn't change a fact that I want to use Typhoon without defining factory manually, so the question is still actual.


Source: (StackOverflow)

Typhoon: How to get an instance conforming to a protocol for production, and another for tests?

I've defined an ApplicationAssembly in Typhoon.

So what I want to do is say: "This class X needs to be injected with something conforming to the Foo protocol. This is a RealFoo, this is a TestFoo. When I'm running X in real life, I want it to get a RealFoo, but when I'm running my integration tests, I want it to get a TestFoo".

How can I do this?


Source: (StackOverflow)

Can dependency injection like Typhoon replace multiple singletons?

I have an app that has about 11 different Singleton instances used throughout the many app's methods and classes; it's getting out of hand, and I want to replace all of them with dependency injection, like Typhoon. However, I am unable to find any doc, sample or mention of how to replace the singletons with dependency injection, including Typhoon. For instance, do I use multiple instances of Typhoon, replacing each singleton with an instance of Typhoon?


Source: (StackOverflow)

Typhoon: Assembly and Storyboard-Created ViewControllers

How would I use Typhoon with iOS storyboards where view controllers are generated implicitly by the system? Would I have to do something special in the prepareForSegue methods?


Source: (StackOverflow)

Typhoon - Runtime Configurable Components Using Storyboard

When my application starts I fetch a remote config file containing information (URLs, etc) required to configure other dependencies.

After I fetch the remote config I have a Config object that I need to supply to other TyphoonDefinitions.

Now I am also using the plist storyboard integration.

I was originally going down the path of injecting the assembly into the ViewController that loads the Config object, and when I receive the remote config and create the Config object, I would somehow set it as a property on the assembly. I did this hoping that I could then use the property in the definitions, but this did not work and I got:

2014-10-22 21:18:06.203 four[39840:516543] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'No component matching id 'setConfig:'.'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010a3e63f5 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010a07fbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010a3e632d +[NSException raise:format:] + 205
    3   four                                0x00000001070a011d -[TyphoonComponentFactory componentForKey:args:] + 148
    4   CoreFoundation                      0x000000010a2de22c __invoking___ + 140
    5   CoreFoundation                      0x000000010a2de082 -[NSInvocation invoke] + 290
    6   CoreFoundation                      0x000000010a36d456 -[NSInvocation invokeWithTarget:] + 54
    7   four                                0x000000010709d358 -[TyphoonBlockComponentFactory forwardInvocation:] + 276

Is there any way for me to inject an object into an assembly at runtime?

Is there a cleaner way to do what I'm trying to do?

I was reading about run-time arguments which sounds like what I need, but I really don't understand the docs.

For example, I have this as a definition. I need to pass the runtime Config object as a parameter to the constructor.

- (id<ApiService>)apiService
{
    return [TyphoonDefinition withClass:[ApiService class] configuration:^(TyphoonDefinition* definition) {}];
}

Source: (StackOverflow)

Typhoon with singleton AppDelegate

I'm using typhoon with 'Plist integration'

I've defined the AppDelegate as follows inside an assembly:

- (AppDelegate *)appDelegate {
    return [TyphoonDefinition withClass:[AppDelegate class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(window)];
        definition.scope = TyphoonScopeSingleton;
    }];
}

Inside window, I have a rootViewController with a delegate that it's implemented by AppDelegate.

- (RootViewController *)rootViewController {
    return [TyphoonDefinition withClass:[RootViewController class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(delegate)]; 
    }];
}

The problem is that the delegate is set with another instance of AppDeleaate. I've set a breakpoint inside the AppDelegate init and indeed it's called twice.

I know that a solution would be to manually set the delegate inside the AppDelegate during runtime, but I would like this to be handled by typhoon.

Note: I haven't tried it but this same thing may happen with view controllers created by storyboards.


Source: (StackOverflow)

Can't inject property, setter selector not found

Using Typhoon and Swift, I am setting up my project and I have this problem. I have a class TPLAddInteractor this way

class TPLAddInteractor: NSObject, TPLAddInteractorInput {

    var output: TPLAddInteractorOutput?
    var dataManager: TPLDataManagerInterface?
}

My assembly looks like this

class TPLAddAssembly: TyphoonAssembly {

    var applicationAssembly: TPLApplicationAssembly?

    dynamic func addInteractor() -> AnyObject {

        return TyphoonDefinition.withClass(TPLAddInteractor.self) {
            (definition) in

            definition.injectProperty("output", with: self.addPresenter())
            definition.injectProperty("dataManager", with: self.applicationAssembly?.dataManager())
        }
    }

    dynamic func addPresenter() -> AnyObject {

        return TyphoonDefinition.withClass(TPLAddPresenter.self) {
            (definition) in

            definition.injectProperty("interactor", with: self.addInteractor())
        }
    }
}

And then I receive this error right after running the app:

reason: 'Can't inject property 'dataManager' for object '<TPL.TPLAddInteractor: 0x7ff5b2d2bcf0>'. Setter selector not found. Make sure that property exists and writable'

I am reading the Swift example of Typhoon and I don't see anything unusual in my code. But I am new on Swift so maybe I'm missing something.

Thanks


Source: (StackOverflow)

Injecting a view controller from a storyboard using Typhoon and Swift

What is the proper way to inject a UIViewController instantiated from a UIStoryboard using Typhoon and swift?

I can't find any clear examples of this in either of the sample apps, and when I translate the Objective C code from the documentation it throws an exception.

Below is the code from my AppAssembly:

public dynamic func loginViewController() -> LoginViewController {
    return TyphoonDefinition.withClass(LoginViewController.self) {
        (definition) in

        definition.injectProperty("socialClient",with:self.coreComponents.socialClient())
        //definition.scope = TyphoonScope.Singleton
    } as LoginViewController
}

And this is the exception that gets thrown:

0x10636ca1c:  jne    0x10636ca10               ; swift_dynamicCastClassUnconditional + 48
0x10636ca1e:  leaq   0x36b3d(%rip), %rax       ; "Swift dynamic cast failed"
0x10636ca25:  movq   %rax, 0xb4a2c(%rip)       ; gCRAnnotations + 8
0x10636ca2c:  int3   
0x10636ca2d:  movq   %rdi, %rax
0x10636ca30:  popq   %rbp
0x10636ca31:  retq   
0x10636ca32:  nopw   %cs:(%rax,%rax)

The "Swift dynamic cast failed" leads me to believe that what was possible using Objective C is just not possible using Swift.

Has anyone been able to make this work? Any assistance would be greatly appreciated. The library looks really nice and I really want to use it.


Source: (StackOverflow)

TyphoonPatcher for mocking in unit tests

I have Assembly:

@interface MDUIAssembly : TyphoonAssembly

@property (nonatomic, strong, readonly) MDServiceAssembly *services;
@property (nonatomic, strong, readonly) MDModelAssembly *models;

- (id)choiceController;

@end

@implementation MDUIAssembly

- (void)resolveCollaboratingAssemblies
{
    _services = [TyphoonCollaboratingAssemblyProxy proxy];
    _models = [TyphoonCollaboratingAssemblyProxy proxy];
}

- (id)choiceController
{
    return [TyphoonDefinition withClass:[MDChoiceViewController class]
                          configuration: ^(TyphoonDefinition *definition) {
        [definition useInitializer:@selector(initWithAnalytics:diary:)
                        parameters: ^(TyphoonMethod *initializer) {
            [initializer injectParameterWith:[_services analytics]];
            [initializer injectParameterWith:[_models diary]];
        }];
    }];
}

@end

Here what I'm trying to do in tests:

- (void)setUp
{
    patcher = [TyphoonPatcher new];
    MDUIAssembly *ui = (id) [TyphoonComponentFactory defaultFactory];
    [patcher patchDefinition:[ui choiceController] withObject:^id{
       return mock([MDChoiceViewController class]);
    }];
    [[TyphoonComponentFactory defaultFactory] attachPostProcessor:patcher];
}

- (void) tearDown 
{
   [super tearDown];
   [patcher rollback];
}

Unfortunately my setUp fails with next message:

-[MDChoiceViewController key]: unrecognized selector sent to instance 0xbb8aaf0

What I'm doing wrong?


Source: (StackOverflow)

How do you pass data from one ViewController to the next with TyphoonStoryboard?

I've got the simplest possible application powered by a storyboard.

Screenie

We've got a UINavigationController, and view controllers A and B.

A has a textfield that the user is supposed to type their name into. When the user touches a button, then it segues into B, showing "Hi, [NAME]!"

How do I pass the user-entered name from A to B with Typhoon?

With Typhoon, I presume that it lets me avoid using -prepareForSegue:sender:, which is just evil from a DI perspective because it requires coupling between what otherwise would be totally unrelated View Controllers. (e.g. viewControllerB.nameToDisplay = self.textField.text;)


Source: (StackOverflow)

TyphoonStoryboard problems

i'm trying to instantiateInitial viewControllers manually and stuck with next thing.

This is working:

-(TyphoonStoryboard *)storyboard {
    return [TyphoonDefinition withClass:[TyphoonStoryboard class] configuration:^(TyphoonDefinition* definition) {
        [definition useInitializer:@selector(storyboardWithName:factory:bundle:) parameters:^(TyphoonMethod *initializer) {
            [initializer injectParameterWith:@"Diary"];
            [initializer injectParameterWith:self];
            [initializer injectParameterWith:[NSBundle mainBundle]];
        }];

        definition.scope = TyphoonScopeSingleton;
}];
}

-(LADiaryMainViewController *)mainViewController {
    return [TyphoonDefinition withFactory:[self storyboard] selector:@selector(instantiateInitialViewController)];
}

and this one is not working:

-(TyphoonStoryboard *)storyboardWithName:(NSString *)name {
    return [TyphoonDefinition withClass:[TyphoonStoryboard class] configuration:^(TyphoonDefinition* definition) {
        [definition useInitializer:@selector(storyboardWithName:factory:bundle:) parameters:^(TyphoonMethod *initializer) {
            [initializer injectParameterWith:name];
            [initializer injectParameterWith:self];
            [initializer injectParameterWith:[NSBundle mainBundle]];
        }];
    }];
}

-(LADiaryMainViewController *)mainViewController {
    return [TyphoonDefinition withFactory:[self storyboardWithName:@"Diary"] selector:@selector(instantiateInitialViewController)];
}

Second way is crashes with: [__NSArrayM insertObject:atIndex:]: object cannot be nil


Source: (StackOverflow)

Swift Typhoon error in tests target - not subclass of Typhoon Assembly

I am trying to set up the Typhoon framework with an example project and it works fine when I run the simulator but its giving me an error when I try to run tests. The error is the following:

NSInvalidArgumentException', reason: 'Class 'DI_Example.MyAssembly' is not a sub-class of TyphoonAssembly'

Now, I read here and here that this is caused by the Typhoon package being linked twice because of CocoaPods. So this is my Podfile and it doesn't seem that it should be linked it twice

platform :ios, '8.0'

target 'DI_Example', :exclusive => true do
    pod 'Typhoon', '~> 2.3' end

target 'DI_ExampleTests', :exclusive => true do end

inhibit_all_warnings!

Also when I change the tests target from applicaiton-style to logic-style everything seems to work fine (I am assuming because the package is not imported twice). Can anyone spot a problem with what I am doing?

It seems that the error is thrown before even hitting my test so I am guessing it has to do with linking the two targets

Here is my test (which is passing if I set the Host Application to None

var controller: HomeViewController!
override func setUp() {
    super.setUp()
    let ctrlAssembly = ControllersAssembly()
    let blAssembly = BusinessLogicAssembly()
    ctrlAssembly.blAssembly = blAssembly
    let factory = TyphoonBlockComponentFactory(assemblies: [blAssembly, ctrlAssembly])
    let configurer = TyphoonConfigPostProcessor()
    configurer.useResourceWithName("Info.plist")
    factory.attachPostProcessor(configurer)


    controller = factory.componentForKey("homeViewController") as HomeViewController
}

func testControllerTitle() {
    // Arrange

    // Act
    controller.viewDidLoad()

    // Assert
    println(controller.title)
    XCTAssertTrue(controller.title == "Root View", "Title is set")
}

Source: (StackOverflow)