Fast nesting of Typhoon component properties does not work
I am using swift with typhoon and somehow my components are not injected via property injection. For simple types like Strings
, it works. I have provided a simple example that explains the problem. The output shows the result where serviceB
has a null reference to serviceA
. All properties are String
set correctly and no error occurs. What am I doing wrong here?
XCode: 6-beta5, typhoon: 2.1.0
MYServiceA.swift
@objc(MYServiceA) public class MYServiceA : NSObject {
public var text : String!
}
MYServiceB.swift
@objc(MYServiceB) public class MYServiceB : NSObject {
public var text : String!
public var serivceA : MYServiceA!
}
MYAssembly.swift
public class MYAssembly : TyphoonAssembly {
public func serviceA() -> AnyObject {
var definitionBlock : TyphoonDefinitionBlock = {(definition : TyphoonDefinition!) in
definition.injectProperty("text", with: "some a text")
definition.scope = TyphoonScopeSingleton
}
return TyphoonDefinition.withClass(NSClassFromString("MYServiceA"), configuration: definitionBlock)
}
public func serviceB() -> AnyObject {
var definitionBlock : TyphoonDefinitionBlock = {(definition : TyphoonDefinition!) in
definition.injectProperty("text", with: "some b text")
definition.injectProperty("serivceA", with: self.serviceA())
definition.scope = TyphoonScopeSingleton
}
return TyphoonDefinition.withClass(NSClassFromString("MYServiceB"), configuration: definitionBlock)
}
}
AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
var assembly : MYAssembly = MYAssembly()
var factory : TyphoonComponentFactory = TyphoonBlockComponentFactory(assembly: assembly) as TyphoonComponentFactory
factory.makeDefault()
var serviceA : MYServiceA = TyphoonComponentFactory.defaultFactory().componentForKey("serviceA") as MYServiceA
println("MYServiceA")
println("- instance=\(serviceA != nil)")
println("- text=\(serviceA.text)")
var serviceB : MYServiceB = TyphoonComponentFactory.defaultFactory().componentForKey("serviceB") as MYServiceB
println("MYServiceB")
println("- instance=\(serviceB != nil)")
println("- text=\(serviceB.text)")
println("- serviceA.instance=\(serviceB.serivceA != nil)")
return true
}
..
}
Output
MYServiceA
- instance=true
- text=some a text
MYServiceB
- instance=true
- text=some b text
- serviceA.instance=false
source to share
Typhoon builds make good use of the ObjC runtime dispatching features. Assemblies are mirrored and each method is intercepted (using the AOP "around" advice) so that Typhoon has a plan to build each of the components in the application assembly. However, Swift will try to use static / vtable dispatch where possible (which prevents the requested method from being intercepted).
To instruct Swift to do this dynamic dispatch, mark your build methods as "dynamic".
Example: (requires Xcode6 beta 6)
public class MYAssembly : TyphoonAssembly {
public dynamic func serviceA() -> AnyObject {
var definitionBlock : TyphoonDefinitionBlock = {
(definition : TyphoonDefinition!) in
definition.injectProperty("text", with: "some a text")
definition.scope = TyphoonScopeSingleton
}
return TyphoonDefinition.withClass(MYServiceA.classForCoder(),
configuration: definitionBlock)
}
public dynamic func serviceB() -> AnyObject {
var definitionBlock : TyphoonDefinitionBlock = {
(definition : TyphoonDefinition!) in
definition.injectProperty("text", with: "some b text")
definition.injectProperty("serivceA", with: self.serviceA())
definition.scope = TyphoonScopeSingleton
}
return TyphoonDefinition.withClass(MYServiceB.classForCoder(),
configuration: definitionBlock)
}
}
source to share