Closed twyneed closed 10 years ago
FYI: I've send a test-project to info@typhoonframework.org which contains the code from above
Hi @ robbiebubble. Thanks for feedback, very usefull information for us. I investigated the problem, and found that method swizzling is not working properly for swift classes. When you calling swift method in swift - it is not sending message, like objective-c but something like vtable in C++ See the example below:
func funcA() -> String! {
return "funcA"
}
func funcB() -> String! {
return "funcB"
}
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
var methodA: Method = class_getInstanceMethod(object_getClass(self), Selector.convertFromStringLiteral("funcA"))
var methodB: Method = class_getInstanceMethod(object_getClass(self), Selector.convertFromStringLiteral("funcB"))
method_exchangeImplementations(methodA, methodB)
println("funcA = \(self.funcA())")
let key = "funcA"
println("funcA = \(self.valueForKey(key))")
return true
}
The output will be
func = funcA
func = funcB
This example shows that swizzling works, but only when sending message, for example when calling valueForKey(key)
And swizzling doesnt works when direct method calling. Seems that it works like C function calls.
This is the reason why Typhoon didn't work properly for swift-based assemblies. We will work to fix that (I already have few ideas). But for now, use valueForKey(key)
approach.
@alexgarbarev Thx for (fast) investigation! Works like a charm :)
MYAssembly.swift
...
definition.injectProperty("serivceA", with: self.valueForKey("serviceA"))
...
Output
...
- serviceA.instance=true
...
In the latest beta of Swift, I think you have to do this:
. . otherwise they're candidates for inline or 'performance enhancing' even if the assembly is marked '@objc'. Thanks to @hsuanyat for this advice.
Add the word 'dynamic' after 'func'
@robbiebubble,
@alexgarbarev and I have just been having a discussion:
We think:
. . . Typhoon assemblies make good use of the ObjC runtime's dyanmic dispatch features, which current versions of Swift will often second guess.
I you're writing a serious app, and have a deadline we recommend this approach. Meanwhile, if you're doing research, then your feedback is incredibly valuable.
I you're writing a serious app, and have a deadline we recommend this approach
As usual, thats the case. To be honest i didn't expected to get that incredible (fast + working) feedback to my questions regarding typhoon (i know this won't always be case because all of you probably have to do things beside). But because of that and as long as i got a fallback-solution (e.g. moving the assemblies to an objective-c class which isn't a big deal) i will stick on the "swift-way" and try to get as far as possible.
:+1: That will be very helpful for us. . It depends how things evolve with Swift, but we think Swift-style assemblies will work somewhat differently to the Objective-C way.
Aleksey did a couple of hours research yesterday and found:
var anotherAssembly : AnyObject!
override init() {
super.init()
self.anotherAssembly = TyphoonCollaboratingAssemblyProxy()
}
. . normally Typhoon will detect this and do it for you, but it doesn't happen in Swift!
Using dynamic fixes this, as shown in 'Swift Quick Start'
Using dynamic fixes this, as shown in 'Swift Quick Start'
@jasperblues: does this include the following?
Runtime arguments - one of the best features of Typhoon - don't work at all :(
@bradfeehan runtime args should work AFAIK
Example
Given:
public dynamic func wanderingKnight(homeFort : Fort) -> AnyObject {
return TyphoonDefinition.withClass(Knight.self) {
(definition) in
definition.useInitializer("initWithQuest:") {
(initializer) in
initializer.injectParameterWith(self.defaultQuest())
}
definition.injectProperty("homeFort", with: homeFort)
}
}
Then:
internal func test_injects_runtime_args() {
let assembly = SwiftMiddleAgesAssembly()
TyphoonAssemblyActivator.withAssembly(assembly).activate()
let fort = Fort()
let knight = assembly.wanderingKnight(fort) as Knight
println(knight.description())
XCTAssertTrue(knight.isKindOfClass(Knight.self))
XCTAssertNotNil(knight.homeFort)
}
@bradfeehan Also note this issue is a duplicate of #286
i'm using swift with typhoon and somehow my components don't get injected through property-injection. For simple types like
Strings
it is working. I provided a simple example which explains the problem. The Output shows the result whereserviceB
has a null reference toserviceA
. AllString
properties are set properly and no error is thrown. What am i'm doing wrong here?XCode: 6-beta5 ,Typhoon: 2.1.0
MYServiceA.swift
MYServiceB.swift
MYAssembly.swift
AppDelegate.swift
Output