4
votes

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?

2
See answer from Aleksey. As long as plist integration is used the storyboard throughout your application will be a TyphoonStoryboard already associated with a TyphoonComponentFactory matching the assemblies in the plist. - Jasper Blues
Sorry. Documentation for TyphoonStoryboards in the User Guide was misleading. This has been corrected. - Jasper Blues

2 Answers

5
votes

it appears I have to remove the UILaunchStoryboardName and UIMainStoryboardFile from the application plist file, and use a TyphoonStoryboard like so

Incorrect. You can combine UIMainStoryboardFile (UILaunchStoryboardName) and TyphoonInitialAssemblies keys in your info.plist file.

In that case, created storyboard will be TyphoonStoryboard and has typhoon factory (created with specified in plist assemblies).

You can use storyboards exactly as you'd normally use them, with the added benefit that dependencies will also be injected, according to the definitions in your one ore more TyphoonAssembly classes.

3
votes

As Aleksey says in his answer, as long as plist integration is used, along with the usual UILaunchStoryboardName and UIMainStoryboardFile, then Typhoon will ensure that any Storyboard is a TyphoonStoryboard. Use exactly as with a normal storyboard, with the added benefit that dependencies will be injected according to the definitions in your TyphoonAssembly classes.

The TyphoonComponentFactory will be retained by the storyboard and so will persist throughout the lifecycle of your app.


Outside of Storyboards: (ie MacOS apps, utilities, etc)

The TyphoonComopnentFactory is indeed designed to be retained throughout the full life-cycle of your app. (Although you could do something else if you wished).

Key concept:

  • You can use the TyphoonComponentFactory as is.
  • Also, any of your assembly interfaces can pose in front of the TyphoonComponentFactory. At build-time an assembly returns definitions. At run-time it returns built components.

There are two ways to retain the TyphoonComponentFactory when proceeding from one object-graph to another. We call this making of your components 'Typhoon aware'.


Approach 1: Inject the assembly:

- (MyAppDelegate *)appDelegate
{
    return [TyphoonDefinition withClass:[MyAppDelegate class] 
        configuration:^(TyphoonDefinition *definition)
    {
        //Other injections . . . 
        [definition injectProperty:@selector(factory) with:self];
    }];
}

The above example injects the TyphoonComponentFactory into a property called factory.

  • When you inject the assembly it can be used as a TyphoonComponentFactory.
  • It can also be used as any of your assembly types. For example, you could declare a property components of type CoreCompopnents and inject the assembly as that.

More info on this feature can be found in the User Guide here.


Approach 2: Use callback hook:

Another way of making a component 'Typhoon aware' is to use Typhoon's callback hooks. by overriding NSObject category methods:

typhoonSetFactory:(id)thefactory

As with the other approach above, the factory can be used as a TyphoonComponentFactory or any of your assembly interfaces my pose in front, both of the following are fine:

typohoonSetFactory:(TyphoonComponentFactory*)factory
{
    //Do something with factory
}

typhoonSetFactory:(ApplicationAssembly*)assembly
{
    //Do something with assembly
}

Of the two approaches, use the one that suits you best. We recommend the former, as it 'non-invasive' meaning your own classes don't directly call any Typhoon APIs. If you ever wished to migrate away from Typhoon, you would simply provide an alternative implementation of the assembly.



Proceeding from one object graph to another:

Once a component is 'Typhoon aware' using either of the above methods, we can use this to proceed from one object graph to another.

  • The default scope for Typhoon is TyphoonScopeObjectGraph, meaning you can load a view controller, including any delegates and circular references. Upon completion, it will be discarded from memory.
  • Meanwhile any components of TyphoonScopeSingleton (or TyphoonScopeWeakSingleton) will be retained.

More information on this feature is in the User Guide here.



Summary:

  • The assembly follows normal Objective-C/Swift memory rules. So as long as its being used by at least one of your classes, it will continue to persist. Using the process of 'proceeding from one object graph to another' described above means that it will persist throughout the life-cycle of your app.

stackoverflow.com/questions/26492175/typhoon-storyboard-integration