Typhoon and #objc limitation in protocols - ios

Is there like an official workaround with protocols and types that are not supported in Object C
As an example, I have a protocol that returns a reactive cocoa signal producer
public protocol PLoginService {
func login(username:String,password:String) -> SignalProducer<Bool,NSError>
}
If I use #objc on the protocol, then I will get the compiler error that the return type is not supported in Objective C. I will have a lot of constructions like this, so I was wondering what I can do in order to benefit from the Typhoon magic

The current version of Typhoon is a reflective and dynamic dependency injection container, and therefore relies on the full Objective-C run-time. This means that, unfortunately, all protocols that will pass through Typhoon must have the #objc directive. Also, anything that Typhoon injects must be an Objective-C compatible type.
We're currently doing R&D on a pure Swift version of Typhoon, and you'd be most welcome to participate in the development of that project on Github.

Related

does all the code called after #objc need to be Objective-C compliant?

When I add a function as a target with #selector to a UIButton, I should mark it as #objc, and that's ok. But the problem is that every function and method that #objc function calls, must be Objective-C compliant, otherwise, app crashes.
For example, when I use Swift enum ( I declared that enum as #objc, too), it crashes with this error unrecognized selector sent to instance
Is it an expected behavior working with #Objc, or I am doing something wrong?
And if it is, is there a workaround or I should make everything called by #objc, objective-C compliant ( in some cases, I need to re-write a big bunch of code)?
#objc attribute makes your Swift API available in Objective-C & Objective-C runtime.
After Swift 4 version launched, Few inference cases of #objc removed. This means in few additional cases where before the #objc header was inferred by the Swift compiler, in Swift 4 not inferred.
So by this cases you can now understand what causes the issue & how to use the #objc.
Make sure you are using swift language version 4 or more updated. From targets -> Build settings find Swift Language version to see what version you are using.
I hope it helps.
After experimenting a lot with the code, I noticed that the problem was rising from saving a custom object to UserDefaults, without archiving it using NSKeyedArchiver.

Objective-C Generated Interface Header and CocoaPods

Once again, I come to the hive-mind for assistence!
I'm using CocoaPods and I have the X-swift.h to expose some Swift code toObjective-C`.
Imagine the following situation:
NetworkService inherits Siesta's Service class (Siesta added via CocoaPods) and is public. Since Siesta's Service class is in fact a NSObject, my NetworkService type will get publicly exposed via the Objective-C via the X-swift.h header and the compiler will send grief and tears my way since the X-swift.h doesn't know what a Service (or BOSService to be precise) is.
The X-swift.h header does not reference the frameworks provided by CocoaPods, so the header has no idea what some of the types from libraries added via CocoaPods are.
Another example of this is the GoogleMapsSDK. Conforming a Swift type to GMSMapViewDelegate requires it to be a NSObject, thus automatically exposing it via the X-swift.h header and causing the same build issue.
I've solved these issues temporarily by wrapping these NSObject types with pure Swift types (so they don't get exported via the X-swift.h header), but I feel there has to be a more robust solution to this.
Looking forward to hearing thoughts about this!

Typhoon Framework: Swift or Objective-C

Which language is preferable when developing with Typhoon framework, Swift or Objective-C?
I can't answer that question directly, however I can give you the information with which to come to your own decision:
Typhoon is a reflective, dynamic dependency injection container and takes advantage of the full Objective-C runtime. Pure Swift classes - ones that do not derive from NSObject - are Objective-C classes "under the hood" but have the following features:
The Objective-C runtime's reflection methods will not work.
They use C++ style inline, static or vtable dispatch which essentially prevents dynamic runtime augmentation of classes. Swift is a static language not just in regards to its time system, but also in this regard.
Answer:
You can use whichever language you prefer.
But if you're working in Swift you should be aware:
Classes being injected by Typhoon should derive from NSObject.
When it comes to Cocoa or Cocoa-touch you'll be working with UIViewControllers, UIViews and so forth, so we don't see this as a problem in the near future. However, eventually we'd like to provide an alternative version of Typhoon that works for "pure" Swift using clojures or perhaps compile-time instrumentation.

How can I find out the Objective-C generics type?

Xcode 7 contains an Objective-C variant, where you can define a type-hint for (homogenous) NSArray return values and properties, defined such as NSArray<UIImage*>.
I'd like to use this feature to rewrite my JSON-deserializer class (which needs such kind of type hints – previously I have solved this by adding a -(Class)jsonHintForKey:(NSString*)key to my classes that have homogenous arrays as properties.)
Do you know whether (and if so, how) I can use the Objective-C runtime to get the class of this new type hint at runtime?
The lightweight generics introduced in Xcode 7 are just compile time hints to help the compiler raise warnings, but at run time you get the same old behavior with your variable being just NSArrays of ids.
Source: WWDC '15 "Swift and Objective-C Interoperability" session
See the transcript of the talk:
So the entire lightweight generics feature is based on a type erasure model. Which means that the compiler has all of this rich static type information but it erases that information when generating code.
It is not possible to do that.
Generics were introduced in objective-c to improve the bridge between swift and objective-c. The advantage it gives to objective-c is only useful at compile time, and I that information is lost at runtime.

Should A Swift Class Be Prefixed To Avoid Potential Objective-C Compatibility Collision Issues

To provide cross compatibility, Swift allows for the generation of a bridging header so that Objective-C can communicate with Swift classes.
Due to Swift's wonderful namespacing we no longer need to worry about prefixing our Swift files as they are namespaced by their containing framework. A UIView for instance is implicitly namespaces as UIKit.UIView.
Now that Apple are pushing frameworks, I was wondering what the best practices are to avoid header collision when there exists two swift bridging headers with the same symbols.
An example: Say we have two frameworks that have declared a Swift class called Downloader. The Downloader provides the interface: downloadWithURL(url: NSURL)
Generating a bridging header will yield a Downloader-Swift.h file for both of these frameworks. Thus causing a collision. What are the best practices to avoid this?
According to Apple's engineers the <#Module Name#>-Swift.h header uses a macro that mangles the name so as to avoid conflicts (see WWDC video Swift Interoperability In Depth, beginning at 45 min, 40 sec). They gave an example of a Document Swift class:
SWIFT_CLASS("_TtC5MyApp10Document")
#interface Document : UIDocument
// rest of the interface...
To your Swift code, the class will be available as MyApp.Document, if MyApp is the module it is in. So, if you have two Swift classes of the same name coming from different modules – say, one is your own and the other from an open source Swift framework SomeFramework – they will be available to your Swift code as MyApp.Document and SomeFramework.Document...
On the Obj-C side, however, importing these two classes into the same lexical scope leads to Duplicate interface definition for class 'Document' compiler error. That's just Obj-C... In the vast majority of cases, though, this will not be an issue since you can still import these two classes across the app as long as they do not trespass each other's territory. Indeed, how often would you want to use MyApp.Document and SomeFramework.Document in the same module of your app? As we are moving into swifter times, I'm not sure this particular issue warrants a particular strategy, compared to so many urgent issues, such as, multicore, distributed, functional, haptic, anticipative, wearable, autonomous, etc...

Resources