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.
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.
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(_:));
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.
As I'm not a C++ developper, I would like to know if it is possible to extend the b2ContactListener class directly with Objective-C, or if I have to wrap the b2ContactListener.
Thank you.
To use box2d with Cocoa requires Objective-C++. . this is a powerful language and a fun way to learn C++.
One of the rules of Objective-C++, is that an Objective-C class cannot extend a C++ class (and vise-versa), thus it is indeed necessary to use composition instead of inheritance (wrap in other words). . . I'm using the term composition here, since "composition vs inheritance" is a common design strategy to achieve the same outcome.
You have to wrap it. There's no way to subclass a C++ class with an Objective-C or Obj-C++ class. So either just create a wrapper in Objective-C++ or create a C++ class to extend it. It should also be noted that files with the extension .mm will be compiled as "Objective-C++" instead of .m to Objective-C.
In Java, when you override a method, you are advised (almost forced) to add the #Override annotation. Is there a convention to mark (either in comments, or by some other mechanism) overridden methods in the Objective-C world?
No. All methods in Objective-C are sent via Objective-C's messaging, so all methods can be overridden. That's part of the language.
There's no convention for marking this, either. It's part of the language that it happens, and if you were to comment otherwise it'd just be confusing when you did it later, accidentally or intentionally.
I'm not sure if Xcode does this, but the AppCode IDE from Jetbrains automatically annotates overridden methods with the little blue override badge in the margin, like so:
. . further to that (also shown), I also like to create some live templates (aka code-snippets in Xcode) to annotate overridden methods with a #pragma tag. I find that it helps to define a standard structure in this order:
class methods
initialization & destruction
public methods / protocol methods
overridden methods
private methods
and by having Live Templates/Code Snippets I can just type 'override [tab]' and the IDE will create the #pragma tag for me.
. . perhaps you could even use OCLint to check that this structure is adhered to.
No, not really.
It doesn't seem to matter as much, probably because of the dynamic dispatch.