-
Notifications
You must be signed in to change notification settings - Fork 268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loading object from assembly crashes only in release mode #310
Comments
Unfortunately Swift can perform some optimizations of UIKit or NSFoundation classes resulting in methods being inlined or invoked in a static fashion, even if the method is overridden and marked 'dynamic'. It prevents runtime method invocation that is required by Typhoon. The workaround is to provide a custom initializer instead of using one of the Foundation ones. Eg MyViewController.initWithNibName:bundle can cause the same problem, but using a custom initializer won't. Although possible to workaround, this is quite a limitation and we want to make this more clear in the Typhoon docs. Meantime, we'll need to see some more code to help. Related #286 . . we've raised a Radar bug about this. |
If I use |
Oops. Didn't see you were using "one of your own" classes. Did your try marking |
ie, you can just mark the method as dynamic, like this: public dynamic convenience init(celciusString : String) {
let fahrenheit = NSDecimalNumber(string: celciusString)
.decimalNumberByMultiplyingBy(9)
.decimalNumberByDividingBy(5)
.decimalNumberByAdding(32)
self.init(temperatureInFahrenheit : fahrenheit)
} Having been marked as dynamic, it will use dynamic dispatch and thus allow reflective invocation, as required by Typhoon / meta-programming. NB: There are some edge cases (#286) where this doesn't work with UIKit/Foundation classes. |
Yes, I tried mark the method as |
Not good. Since its a convenience initializer that's chaining off the main one can you also try marking that dynamic? public dynamic init(temperatureInFahrenheit : NSDecimalNumber) {
_temperatureInFahrenheit = temperatureInFahrenheit;
_shortFormatter = NSNumberFormatter()
_shortFormatter.minimumFractionDigits = 0;
_shortFormatter.maximumFractionDigits = 0;
_longFormatter = NSNumberFormatter()
_longFormatter.minimumFractionDigits = 0
_longFormatter.maximumFractionDigits = 1
} |
It still doesn't work. |
Will investigate ASAP. Possible to show code on a fork? Meantime, if this is an urgent problem, suggest using property injection. |
I have uploaded the code. It isn't an urgent problem. I am investigating Typhoon and may use it in the future. |
Objective-C is very stable - there are hundreds of Typhoon apps deployed, and we use it daily on our own projects. Typhoon with Swift remains somewhat experimental. Swift, having no native reflection, and aggressively optimizing towards static and vtable dispatch, means there are some quirks. We are waiting to see if Apple will improve interoperability with Objective-C or instead provide native solutions to reflection and runtime method interception (AOP). |
Thanks for the information. Since, Swift isn't really stable right now, I intend use both Objc and Swift in my next project, ObjC for the business part and Swift for UI part. Could you please give me some advise about my approach? Is it a good way? Thanks very much. |
I couldn't really say, since it depends on the project, team skills, etc. I'm sure for this specific case you'd know better than me. As for using Typhoon in a Swift project. It will be more complicated than with Typhoon with Objective-C. We don't currently use Typhoon/Swift ourselves on our own projects yet. Based on the bug reports, for the most part it works, however it is sometimes necessary to make code changes to work around issues. (eg use property injection instead of initializer injection, as suggested above). Its up to you if you think this is acceptable, but we've marked the issue as 'show-stopper'. DI Options with Swift
|
I prefer to use dependency injection in my next project and my project also requires to use some C++ libs, so that I will use objC and keep an eye on this framework. Until it is fully compatible with Swift, I will switch the UI code to using Swift. Anyway, thank you for help. |
You're welcome. Thanks for choosing Typhoon :) |
I want to test the
TyphoonScope
, so that in your swift examplePocketForecast
, I add this method inApplicationAssembly
:public dynamic func customObj() -> AnyObject { return TyphoonDefinition.withClass(Temperature.self) { (definition) in definition.scope = .LazySingleton definition.useInitializer("initWithCelciusString:") { (initializer) in initializer.injectParameterWith("1000") } } }
Now what I want is when I perform an action I will call my
customObj
and check its address.So, in
RootViewController
'sshowCitiesListController
, I calllet tempObj = self.assembly.customObj()
. (I should create a button to do that, but forgive me, I just want a quick test).This code runs well in debug mode but not in release mode and throws exception
[NSUserDefaults copyWithZone:]: unrecognized selector sent to instance 0x7fab98e106f0
.Also I really want to know why it crashes inside
NSUserDefaults
while I don't make any call toNSUserDefaults
class.Thanks.
The text was updated successfully, but these errors were encountered: