I have a .framework that I build in Objective-C and I use it in iPhone project built using Swift 4. The .framework uses a delegate to call methods as required.
I've noticed that depending on whether I use the word 'To' in my protocol method signature I get a very different implementation in Swift. For example if I define my protocol methods as:
- (void)myApiExited:(Api*)api;
- (void)myApiReadyToPresentViewController:(Api*)api;
Then in my Swift project I get:
func myApiExited(_ api:XPINApi!) {}
func myApiReady(toPresentViewController api: Api!) {}
If however I change the method signature to not include the word 'To' then the method name in the implementation becomes what I would expect it to be:
- (void)myApiReadyPresentViewController:(Api*)api;
Result:
func myApiReadyPresentViewController(_ api: Api!) {}
It is very strange to me that the word 'To' would cause this. I expect the method name in my implementation to be the same as in the protocol. Am I doing something that is wrong or is this some kind of bug.
This is by design, as the Objective-C importer picks up on conventions in Objective-C names to provide more adapted Swift names. I can't find the exhaustive set of rules, but if you want to specify a Swift name, you can use NS_SWIFT_NAME. Off the top of my head, you'd write this:
- (void)myApiReadyToPresentViewController:(Api*)api
NS_SWIFT_NAME(myApiReadyToPresentViewController(_:));
Related
I have a framework target in which most of the classes are written in Objective C. Recently we have started introducing Swift files in the code. We make private Objective C files available to swift code using modules(more on this can be found here).
This approach worked well until recently when I tried subclassing one of my Objective C class using Swift, I got an error in the Generated MyFramework-Swift.h file which said "Module TestSwift not found" where TestSwift is the name of the module I provided in the modulemap file. However, if I try subclassing the classes which are listed in the umbrella header of my framework(public classes), it works.
import TestSwift
#objc public class NewSwiftClass: ExistingObjectiveCClass {
//throws error in the generated MyFramework-Swift.h file while compiling
}
If I keep my swift class internal, it works
import TestSwift
#objc class NewSwiftClass: ExistingObjectiveCClass {
//works fine
}
but I would like to use this Swift class in my Objective C files hence cannot keep it internal.
TL;DR: I'm unable to subclass an existing Objective C class using Swift inside a framework target.
I believe this is impossible in Swift because it's impossible in Objective-C.
If you have a class A in your framework that is not part of your umbrella header, and you want B to subclass it and be in your umbrella header, you can't do it.
You have to declare the inheritance in your interface declaration #interface B: A, which goes in B's header and thus in the umbrella header. But the compiler is going to complain: "What is A?" You could import A's header there, but unlike Swift's import, Objective-C's #import literally drops the contents of A's header into the B header. Which means A is now in the umbrella header too i.e. public.
Mixing Swift with Objective-C isn't magic. The compiler still needs to be able to make a valid Objective-C header that accurately describes the Swift interface. So unless you can think of a way to make Objective-C do this, you can't do it in Swift.
The only alternative I can think of is to change your "is a" relationship into a "has a" relationship i.e.
#objc public class NewSwiftClass {
let parent: ExistingObjectiveCClass
}
obviously you lose most of the benefits of actual inheritance but you'll still have the parent around as a substitute for super. You could also declare a public protocol that both classes conform to to ensure that you get consistency between their methods.
What is the use of bridging header?
Is it just for using Objective-C and Swift code in the same project?
Should we avoid using bridging header?
Say, if there are two third party library which are very similar; one of them is in Objective-C and other is in Swift. Should we use the Swift library or use Objective-C library. Are there any downside of using bridging headers?
Apple has written a great book that covers this in depth. It can be found here:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
I will quote it to answer your questions:
"What is the use of bridging header?
Is it just for using Objective-C and Swift code in the same project?"
To import a set of Objective-C files in the same app target as your Swift code, you rely on an Objective-C bridging header to expose those files to Swift. Xcode offers to create this header file when you add a Swift file to an existing Objective-C app, or an Objective-C file to an existing Swift app.
The answer to this question is yes. It is just there to make Swift and Objective-C work together in the same project.
"Should we avoid using bridging header? Say, if there are two third party library which are very similar; one of them is in Objective-C and other is in Swift. Should we use the Swift library or use Objective-C library. Are there any downside of using bridging headers?"
There are always tradeoffs. The first answer to this is no you should not avoid using a bridging header; however, as far as third party libraries you have to look at many factors. Which one has more functionality? Is it being maintained and/or added to frequently?
Using an Objective-C library will also add things to be aware of and work around. From the book:
Troubleshooting Tips and Reminders
Treat your Swift and Objective-C files as the same collection of code, and watch out for naming collisions.
If you’re working with frameworks, make sure the Defines Module (DEFINES_MODULE) build setting under Packaging is set to “Yes".
If you’re working with the Objective-C bridging header, make sure the Objective-C Bridging Header (SWIFT_OBJC_BRIDGING_HEADER) build setting under Swift Compiler - Code Generation is set to a path to the bridging header file relative to your project (for example, “MyApp/MyApp-Bridging-Header.h").
Xcode uses your product module name (PRODUCT_MODULE_NAME)—not your target name (TARGET_NAME)—when naming the Objective-C bridging header and the generated header for your Swift code. For information on product module naming, see Naming Your Product Module.
To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked #objc.
When you bring Swift code into Objective-C, remember that Objective-C won’t be able to translate certain features that are specific to Swift. For a list, see Using Swift from Objective-C.
If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types before importing the Swift generated header into the Objective-C .m file you want to use your Swift code from.
Swift declarations marked with the private modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with #IBAction, #IBOutlet, or #objc as well.
For app targets, declarations marked with the internal modifier appear in the generated header if the app target has an Objective-C bridging header.
For framework targets, only declarations with the public modifier appear in the generated header. You can still use Swift methods and properties that are marked with the internal modifier from within the Objective-C part of your framework, as long they are declared within a class that inherits from an Objective-C class. For more information on access-level modifiers, see Access Control in The Swift Programming Language (Swift 2.2).
Que : What is the use of bridging header?
Its correct to say, Bridging header allows user to use Objective-C classes/files in their swift code in same project.
A Swift bridging header allows you to communicate with your old Objective-C classes from your Swift classes. You will need one if you plan to keep portions of your codebase in Objective-C. It should be noted that even if you decide to convert all of your code to Swift, some classes or libraries you may use such as SVProgressHUD haven’t been rewritten in Swift and you will need to use a bridging header to use them.
Que : Should we avoid using bridging header?
Considering your question there are 2 possible cases.
case 1 : Lets say your project is developed in Objective-C and now you are developing new features using swift in it, in this case you have to have BridgingHeader as you need access of your Objective-C classes in swift code.
case 2 : If your project is developed in swift then there is no need to have Bridging header, as well if its in only Objective-C and you are not planning to move it in swift then also you don't need it.
Read more about Using swift with cocoa and Objective-C in apple documentation.
Following apple document image indicates usage of Bridging header
No, there are no downsides to using Obj-c code in your Swift project. Bridging header only exposes your Obj-c files to Swift. The two languages can coexist in the same project with no problems, as you can expose your Swift code to the Obj-c just as easily too - xCode will generate a header for all of your public Swift declarations. Although everything is possible, if you start a new project you should stick to one language so the project is easier to understand. For example if you decide on Swift you should only use Obj-c for libraries that are not available in Swift.
The bridging header allows the use of Swift and Objective-C in the same project. There are no downsides to having a bridging header in your project as the two languages can work well together within the same app.
Removing a bridging header from a project after it has been added may cause errors, as it is referenced in other places in the project when it is created.
If you only intend to use one of the two languages, a bridging header is unnecessary. On the other hand, if you are using both Swift and Objective-C, a bridging header is required and will not cause any issues.
Here is a link to find more information on the subject:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
I hope that answered your question. Good luck with your project!
What is the use of bridging header?
You have already got that answer. You're right.
Should we avoid using bridging header?
No. Its good when a third party library developed in Obj-C and may not available in Swift yet. You should use bridging header to have a best library for your app.
It depends which on you choose. In case of networking? If your project is in Obj-C based you can use AFNetworking or with the case of Swift you can use AlamoFire, you can still use AFNetworking in Swift but its not suggestable.
Bridging headers are a great way to get Objective - C code into your Swift project. If you have two libraries, one that is in Swift and one that is in Objective - C, choose the one that will offer more functionality in your app. If they offer the same functionality, I'd just go with the Swift library -> My reasoning: if the Objective-C library isn't widely used and there aren't many tutorials on how to convert the Objective - C code into Swift, it can be very time consuming to figure it out on your own. If you use a Swift library, the code is already formatted in the correct language, saving you time and potentially money (depending on if this is a hobby for you or not). As far as any downsides to using a bridging header, their really isn't! With so many libraries written in Objective-C, you almost need a bridging header in your app. Take, for example, Reachability (Here is a video on implementation in Swift). This is a library that Apple created to handle network interruptions in your app. This is a great tool for developers and requires a bridging header. Here is a great YouTube video on how to use a bridging header, but if you add a header file into your Swift file, Xcode typically asks to crete one for you. Hope this helps!
I have a method declared in Objective-C protocol:
#protocol QMChatConnectionDelegate <NSObject>
#optional
- (void)chatServiceChatDidConnect:(QMChatService *)chatService;
I want to use this method as callback in my .swift file. My question what is difference between using chatServiceChatDidConnect method directly in class body or adding it as part of extension:
class Chat: NSObject, QMChatConnectionDelegate
{
...
func chatServiceChatDidConnect(chatService: QMChatService!) {
print("connected")
}
}
or
class Chat: NSObject, QMChatConnectionDelegate
{
...
}
extension Chat: QMChatConnectionDelegate {
func chatServiceChatDidConnect(chatService: QMChatService!) {
print("connected")
}
}
and do I need to declare it as extension Chat : QMChatConnectionDelegate {} or just extension Chat {}
There are two questions being asked here, so I'll try to address both of them as directly as possible.
What is difference between using chatServiceChatDidConnect method directly in class body or adding it as part of extension?
Depending on what you mean by "difference", the answer is either "nothing" or "very little".
Once your project is compiled, there will be no difference. During compilation, it might take slightly longer, but I doubt the difference is noticeable enough to care. During development, the difference is mostly organizational, but perhaps partly architectural.
If you do not move the extension to a separate file, the difference is going to be purely organizational. If you have a class conforming to multiple protocols or particularly large protocols, organizing the protocol conformance into extensions can be beneficial when it comes to human-parsing of the class.
If you do move the extension into a separate file, you can obtain some architectural differences as well when we consider how the private access modifier works in Swift (or also the default internal when we consider that the extension could be not just a different file, but a different module, but for simplicity sake, let's focus on private).
Consider conforming to a UITableViewDataSource protocol. Conceivably, we might want some helper methods when it comes to returning a cell from tableView(_:cellForRowAtIndexPath:), and if that's the case, tableView(_:cellForRowAtIndexPath:) is probably the only method that actually needs to call those methods. If that's the case, we can create the protocol conformance in an extension in a separate file and mark all of the helper methods as private. Now we've narrowed the scope of those helper methods to just that extension (which should be the only place that needs it).
Do I need to declare it as extension Chat: QMChatConnectionDelegate {} or just extension Chat {}?
The answer to this is it depends.
Certainly, you don't need to mark your class as conforming to a protocol in multiple places. Just one will do. And while extensions can have different access level than the class they extend (a private extension of an internal class for example), they can not have an access level broader than the class they extend (a public extension of an internal class is not allowed, for example).
What makes most sense to me is to not mark the class as conforming to the protocol but mark the extension as conforming to the protocol:
class Chat: NSObject {}
extension Chat: QMChatConnectionDelegate {}
Importantly, when we create our classes & extensions like this, it keeps our code quite modular. Our class shouldn't rely on anything in the extension. It should function entirely without it, and removing the extension allow our class to still work properly (just not for using the QMChatConnection).
First of all extension declaration is valid only from the file scope, so your second example should look like that:
class Chat: NSObject
{
...
}
extension Chat : QMChatConnectionDelegate {
func chatServiceChatDidConnect(chatService: QMChatService!) {
print("connected")
}
Secondly you shouldn't re-declare protocol conformance in both class declaration and extension.
You should treat Swift extension more or less like categories in Objective-C.
Answering your questions, there is no big difference if you declare method conforming to a protocol directly in the class scope or in the extension.
Adding protocol conformance in extensions can have several benefits:
You can add methods implementing certain protocol in a separate file
You can add protocol conformance to existing classes, without modifying their body. So in the end you can add protocol conformance to 3rd party classes
It allows for a nice logical organization of your source code.
I've converted most of my application to Swift. What's left is a number of Objective-C protocols, and some code that should use Swift idioms in place of Objective-C style.
I've done the assembly of my application using Typhoon. Now after converting one of the protocols to Swift, I noticed the intializer was no longer dynamic (required by the DI library). So I tried marking it explicitly dynamic, but got the following error:
Its complaining that the 3rd argument (my Swift protocol) can never participate as part of Objective-C. This seems like it would be a widespread limitation for Swift/ObjC interoperability. Is the only solution to define the protocol in ObjC and have the Swift classes implement that?
The following solution did not work:
public protocol WeatherReportDao : NSObjectProtocol { //Extend NSObjectProtocol
}
It seems that the best work-around is to add the #objc directive to the Swift protocol. Example:
#objc public protocol CityDao {
//etc. . .
}
. . to me, this is archaic, as what I'd really like to communicate is that the protocol requires dyanmic dispatch - something that can go beyond Swift-ObjC interoperability.
Still, it works just fine.
In Objective-C, is there a way to get a class and send messages to it when you have the name of the class as a string? For example, is there a function func where func(#"NSString") == [NSString class]?
The reason that I want to know this is I am building a dynamic linker library for a language I am working on, and I want it to have an interface to Objective-C libraries.
Yes — two, in fact. If you have a Foundation-type framework (e.g. from Cocoa, Cocoa Touch or GNUstep), you can use the NSClassFromString() function, which is precisely the same as your func. If you do not want to depend on a framework, there's a similar runtime function, objc_getClass(), that takes a const char* and returns the named class (or nil if none is found).
You can use NSClassFromString(NSString className) to get the class object from its name.
Hope this helps!