Image for post
Image for post

Tips for creating an iOS Framework

If you are looking for a general step-by-step tutorial on how to create a simple Cocoa Touch framework I recommend the following article:

In this tutorial, I’d like to show you some quick and useful tips which you can apply when designing and developing your iOS frameworks. I include a use-case of working with Objective-C codebase, interfacing with Swift code, as well as error handling. The approaches mentioned below are based on Apple’s official guidelines, as well as on my own experience building Cocoa Touch Frameworks.

I’ve made a quick demo with code examples for both the framework and an app with the framework integrated into it:

Use Namespaces

Namespace prefixes for classes serve a purpose of avoiding pollution of the global namespace. Apple recommends using 3-letter prefixes for third-party framework classes, although they do have a convention to use 2-letter prefixes for their own frameworks (like CL for CoreLocation). For our AwesomeFramework I’m going to use AWE prefix.

Nullables

Nullables were fairly recently introduced to Objective-C for the purpose of bridging pointers to optionals. Unless you specify explicitly, every pointer would turn into a nullable. For example, NSString * would bridge to String? optional in Swift by default.

Nullability specifiers are currently enforced as compiler warnings, and to avoid explicitly specifying nullable/_Nullable or nonnull/_Nonnull for every pointer, you can use audited regions. By using NS_ASSUME_NONNULL_BEGIN you only need to explicitly mark only those pointers that are non-mandatory, except a few notable exceptions, like NSError **, which is always assumed nullable.

Preview Bridged Interface

One of the neat hacks I discovered recently was previewing your bridged Swift interface without building the framework first, which saves a lot of time. To do that, open an Objective-C header and select the four square icon in the top-left corner, then select Counterparts -> Swift Interface.

Image for post
Image for post

Unfortunately, Swift interface preview doesn’t seem to work reliably on large projects. In this case try to clean your derived data 🤞.

Include you framework headers in the umbrella header and make them public

This is commonly overlooked, so I figured I’d mention it here as a reminder.

What I mean by this is if say you have a class with a header MyClass.h, you need to select that header and make sure that target membership in the right panel is specified as Public.

Besides that, don’t forget to include the header itself in your main framework header like this: #include “MyClass.h”

Carthage

When deciding whether to use Cocoapods or Carthage, I use the following rule of thumb: use pods if it’s a third-party library, and Carthage when it’s a library I have control over. This comes from following the most simple path to managing dependencies. I find it fairly straight-forward to setup Carthage for my own libraries, whereas most common third-party libraries come with pods only. Besides, I prefer simplicity of Carthage over easiness of Cocoapods. Cocoapods are easier to install, but if there is any issue the complexity of it could easily become a hassle.

To prepare a Cartage framework, first you need to make your framework scheme shared. To do that, edit your scheme (⌘<) and select Shared. Don’t forget to commit xcshareddata folder in your source control.

Image for post
Image for post

Now, to use the framework for local testing in your main app, create a Cartfile with the following content:

git "file:///directory/to/project" "branch"

To integrate a framework in your main app, you can follow these steps.

Don’t forget to link the framework in the General tab, like this:

Image for post
Image for post

Whenever you make changes to your framework, to make them live in the main app, don’t forget to commit changes to source control and run carthage update in the main app.

Error Handling

This doesn’t relate directly to frameworks per ce, but is more about general API design. When bridging from Objective-C to Swift, it’s important to keep in mind guidelines for error handling in both.

In Objective-C a common error handling practice used in Apple’s own frameworks is C-style, i.e. to have methods which populate NSError**, like this:

- (NSData * _Nullable)encrypt:(NSString *)message error:(NSError **)error;

When you call such method, you’d check if error is nil, like this:

NSError *error = nil;
NSData *encryptedMessage = [MyClass encrypt:@”test” error:&error];
XCTAssertNil(error);

How does this API translate to Swift?

In Swift we want to use try/catch blocks. Good news is that the method signature above automatically translates to

func encrypt(_ message: String) throws -> Data

Pretty neat, huh? The key here is to have the return pointer (NSData* in this example) as nullable and have the error parameter trailing in the method signature.

Now, the bridged method is throwable, and can be handled like this:

guard let encryptedMesaage = try? AWEMainClass.encrypt(“test”) else {
return
}

I find this notation particularly neat, as it combines error handling APIs of try/catch with “golden path” approach of guard-else-return.

Error Handling Continued

How do we actually define and generate errors within our Objective-C framework?

First, we need to define an enum with error constants. I suggest using meaningful comments and naming here to help your API users to distinguish between errors. We can use an enum for that:

typedef NS_ENUM(NSInteger, AWEError) {  /** General error (please don’t abuse it :). */  AWEErrorFail = 1};

Then, generate an error like this:

*error = [NSError errorWithDomain:AWEErrorDomain code:AWEErrorFail userInfo:nil];return nil;

Do you know other common pitfalls when building Cocoa Touch Frameworks? Feel free to comment on this article. Thank you for reading!

Written by

Hacker. Entrepreneur. Jetsetter. Dreamer. @nderkach http://derka.ch

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store