Challenges in projects having both Objective-C and Swift

Swati Wadhera
Mac O’Clock
Published in
5 min readApr 17, 2020

In this article, I am going to share the challenges I faced while integrating Objective-C code into my newly built Swift application.

Recently, I had to revamp my application in terms of design and features and we decided to create a new project in Swift language all together. After sometime, because of tight deadlines, I had to integrate some of the Objective-C written code into my Swift project. I had created my Swift project in pure MVVM architecture with few enhancements. It had its own network layer and its own Image Service. The Objective-C code was in MVC which was the biggest challenge here. So, let's go step by step.

Adding Objective-C Files

Objective-C files can be added in your Swift project by a simple drag and drop. The beauty of XCode is that the moment you add a .h and .m file in your Swift project, it asks you to automatically create a bridging header. A bridging header is a .h file which acts a bridge between Objective-C and Swift. You may import any Objective-C file here to be able to use it in Swift files.

In case you click on “Don’t Create” by mistake, its fine. Don’t panic. You can manually add a .h file and name it as <AppName>-Bridging-Header.h and it works same as the one Xcode created for you.

MyApp-Bridging-Header.h

Using Swift-Code in Objective-C

In case you wish you use Swift code in Objective-C, you may import the swift auto-generated header for your project. No need of importing it in every Objective-C file. Create a constant file like “ObjectiveC-Constants.h” and import this in that file. You should import this file wherever you wish to use Swift code in your project. This file is also useful for creating few constants for your Objective-C Code.

#import "MyApp-Swift.h"

I had created different build configurations for my project such as Debug, Staging, Alpha and given product name in build settings also differently such as

Debug     - MyApp Debug
Staging - MyApp Staging
Alpha - MyApp Alpha
Release - MyApp

This created different Objective-C Generated Header Interfaces for my app for different build configurations. In order you use the correct interface in a configuration, I imported different headers in my ObjectiveC-Constants.h in this way.

#if DEBUG
#import "MyApp_Debug-Swift.h"
#elif STAGING
#import "MyApp_Staging-Swift.h"
#elif ALPHA
#import "MyApp_Alpha-Swift.h"
#else
#import "MyApp-Swift.h"
#endif

Your app will work just fine if you do not do this in debug mode but will give your error while archiving for release mode. You may also keep your name same for each configuration and get rid of this pain but it's easy to identify the apps on the device with the different name while you are giving it to QA team or your beta testers. Also, this pain is just one time... Oouch.. and you are done.

Unable to see Swift Code in Objective-C files

This happens with me all the time so it must be happening with you also. There are a few steps that you need to follow in order to use Swift code in Objective-C files.

  • Make sure the class you need to use is an @objc class and a subclass of NSObject.
@objc
class MyAppSwiftFile: NSObject
  • Make sure the function you need to use is also an @objc function. There are a few restrictions here. You may not be able to add a few type parameters in your function which are not available in objective-c such as CGRect, CGPoint, Int, Float etc.
@objc
func mySwiftFunction() {
print("Hello Swift Function")
}
  • Import the swift class in your Objective C header file as
@class MyAppSwiftFile;
  • Make sure you build the project in case you have freshly created the class or function otherwise there objective-c code will not be generated in your Header Interface file. You can also right-click on the import command and visit your file to see which code has been generated and which not.
Sample class implementation in MyApp-Swift.h

Swift Functions with Default Parameters in Objective-C

We tend to use this very nice feature of Swift in lot of our functions which is giving default values in arguments.

extension UISearchBar {
func
setCustomStyle(barTintColor: UIColor = UIColor.white, backgroundColor: UIColor = UIColor.white, tintColor: UIColor UIColor.black, shadow: Bool = true) {
// some implementation
}
// different function calls
mySearchBar.setCustomStyle()
mySearchBar.setCustomStyle(shadow: false)
mySearchBar.setCustomStyle(tintColor: UIColor.red, shadow: false)

Beautiful isn’t it? In case you haven’t used this feature yet, dude you are missing the fun in Swift.

There’s no concept of default parameters in ObjC.

Now if I want to use this function in my Objective C. I changed my code a little bit by writing @objc in my class and function declaration. Build my project and its objective-c code is generated like this.

I am able to use this in my Objective-C code with ease with only one issue — I had to give values to each of the parameters of the function.

Writing Test Cases

Don’t worry, I am not going to get started about how to write test cases and blah blah. All, I am going to discuss here is about how to import your project here before starting to write test cases. Remember, I mentioned above about different build configurations, they are going to give you pain here again. You will have to import the project in your UnitTest or UITest file like this.

#if DEBUG
@testable import MyApp_Debug
#elif STAGING
#import "MyApp_Staging
#elif ALPHA
#import "MyApp_Alpha
#else
#import "MyApp
#endif

Limitations

  • Swift Struct is not available in Objective-C.
  • Enum only Int types are available in Objective-C.
  • Swift functions with default parameter values are available in Objective-C but you will have to give values to each parameter.
  • Cyclic dependency issues in Objective-C files.
  • Objective-C prefix header file and constants defined like macros are not available in Swift files.
  • Handling different configurations in a mixed-language project may give you build errors sometimes.

Conclusion

You may or may not feel like mixing the two languages in a single project but you might end up doing so at some point in your life so it's better to be prepared for it. I have covered most of the sections and challenges I faced in my project. In case you have any query or find a better way of doing things, do let me know in the comments below.

Thanks for reading 🙌🏼

--

--