7

I need to make an library for iOS (either Framework or static library - I haven't decided yet) that can be used in both Objective-C and Swift projects. What is the best way of doing this? The way I see it I have three options:

  1. Write the library in Objective-C and add support for Swift (bridging headers etc).
  2. Write the library in Swift and add support for Objective-C.
  3. Write two libraries, both in Objective-C and Swift. I really want to avoid this option.

The main requirement here is that it should be as easy for developers to use as possible. Ideally, they should be able to choose their language and not care, or indeed even know, what language the library itself was written in. Can this be done?

Also, I want to be able to distribute the library with CocoaPods, if this has any significance.

pajevic
  • 4,607
  • 4
  • 39
  • 73
  • 1
    option 1 most likely, since as swift goes from version to version, users of your library will have to wait before upgrading if they rely on your library – Fonix Apr 14 '16 at 08:22
  • Thanks for the input Fonix. I hadn't even considered this. – pajevic Apr 14 '16 at 08:23

1 Answers1

9

Option 2. Is out of question (described in detail later)
Option 3. As you said, you should really avoid it.

Option 1 is the best. Just design your API with Obj-C and Swift in mind. What does it mean ?

• Don't use selectors - they're not a Swift standard.
Use nullability to convert to optionals
• Closures and blocks may have the same syntax, but there's a slight difference, watch out for that:

Swift closures and Objective-C blocks are compatible, so you can pass Swift closures to Objective-C methods that expect blocks. Swift closures and functions have the same type, so you can even pass the name of a Swift function.

Closures have similar capture semantics as blocks but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of __block in Objective-C is the default behavior for variables in Swift.

Source: Apple's Using Swift with Cocoa and Objective-C - It explains everything in detail.

You can read more here.

When designing such API you have to know how everything is converted, but if you do it right the users won't notice a difference :)

Module File

Make sure your x.framework is shipped with the modules folder and file inside.

New Xcode generates it for you. This way users can use your Obj-C project in Swift without adding it to a bridging file. So they can just import myLib out of the box.

enter image description here

Why not Swift?


Unfortunately, the most sensible way to distribute a compiled library right now is to write it in Objective-C.

And that's because of one big reason: Swift Binary Compatiblity Problem

While your app’s runtime compatibility is ensured, the Swift language itself will continue to evolve, and the binary interface will also change. To be safe, all components of your app should be built with the same version of Xcode and the Swift compiler to ensure that they work together.

This means that frameworks need to be managed carefully. For instance, if your project uses frameworks to share code with an embedded extension, you will want to build the frameworks, app, and extensions together. It would be dangerous to rely upon binary frameworks that use Swift — especially from third parties. As Swift changes, those frameworks will be incompatible with the rest of your app. When the binary interface stabilizes in a year or two, the Swift runtime will become part of the host OS and this limitation will no longer exist.

Peter Steinberger, the founder of PSPDFKit, which is also a library distributed as a compiled library has ran into the same problem: they're stuck with Obj-C for now and can't use Swift.

michal.ciurus
  • 3,616
  • 17
  • 32
  • Thank you for the answer. Personally I don't have a huge issue with having to stick to Objective-C for now. My sole concern here is how to package the library in a way so that Swift developers don't have to concern themself with Objective-C. – pajevic Apr 14 '16 at 11:32
  • Great points michael, thank you for this. So is there anything in particular I need to do when packing my framework. How to ensure that it can be used with Swift out of the box? – pajevic Apr 14 '16 at 12:06
  • Edited my answer. You don't have to do anything other than make sure you have new Xcode :D – michal.ciurus Apr 14 '16 at 12:32
  • The comments about the module are unnecessary if distributing via CocoaPods. [This](https://github.com/nhgrif/SQLConnect) is an Objective-C library which works perfectly fine from Swift pulled in via CocoaPods. – nhgrif Apr 14 '16 at 12:37
  • Is that the case for a compiled .framework distributed with CocoaPods ? I don't think so. Please note that the library you linked is an open source. It's different. – michal.ciurus Apr 14 '16 at 12:38
  • I think overall, the most important note here is that Objective-C libraries work perfectly fine from Swift without any extra effort, though you should definitely make the extra effort to add nullability annotations and specify generic types on your collections. Even when we get to a more stable version of Swift, by using Swift, we may be cutting off potential library users that are, for example, still trying to support iOS 6. – nhgrif Apr 14 '16 at 12:39
  • @michael Could I please bother you with an additional question? In your answer your write "Don't use selectors - they're not a Swift standard" - what exactly does this mean? I am asking because in my framework I have a delegate protocol with optional methods. Normally I would use the `respondsToSelector:` method with a `@selector()` parameter to check if a method has been implemented on the delegate, but am I not allowed to do this if I want it to be Swift-safe. Or does that only applies to public library methods? – pajevic May 05 '16 at 20:30
  • Sure. It's very easy: selectors aren't a Swift thing. It's an objective-c mechanism. Moreover it doesn't work on pure Swift classes, unless you use a @objc property. More here: http://stackoverflow.com/questions/24007650/selector-in-swift – michal.ciurus May 05 '16 at 20:56
  • Thanks michal. However, I've already seen that post and it doesn't really help me. It taks about how you treat selector-based scenarios _in_ Swift, but I need to know what to do in my Objective-C library so that it will also work for people that use Swift. Do I have to avoid using selectors altogether? – pajevic May 06 '16 at 16:21
  • Yes, you need to avoid using selectors as I written in the answer. Selectors cannot be transformed into any Swift standard like nulability for example – michal.ciurus May 06 '16 at 19:03
  • @michal.ciurus Are you sure you are correct here? :) I actually tested my framework in an Swift app and encountered no issues, even though I am using `respondsToSelector:` and `@selector()`. I think we are fine using selectors **internally** in the framework. – pajevic May 07 '16 at 06:23
  • 2
    Yes, using it internally is fine. You shouldnt use it in the public API. – michal.ciurus May 07 '16 at 11:04
  • Swift has ABI stability now. Could you please update your answer, I'm sure you'll have a lot of great insights. Thanks! :) – Ben Butterworth Jun 06 '21 at 10:33