Appendix A. C, Objective-C, and Swift

This book has been revised for Early Release. It reflects iOS 14, Xcode 12, and Swift 5.3. But screenshots have not been retaken; they still show the Xcode 11 interface.

The APIs for Cocoa and its associated frameworks are written in Objective-C or its underlying base language, C. Messages that you send to Cocoa using Swift are being translated for you into Objective-C. Objects that you send and receive back and forth across the Swift/Objective-C bridge are Objective-C objects. Some objects that you send from Swift to Objective-C are even being translated for you into other object types, or into nonobject types.

This appendix summarizes the relevant linguistic features of C and Objective-C, and describes how Swift interfaces with those features. I do not explain here how to write Objective-C! For example, I’ll talk about Objective-C methods and method declarations, because you need to know how to call an Objective-C method from Swift; but I’m not going to explain how to call an Objective-C method using Objective-C.

The C Language

Objective-C is a superset of C; to put it another way, C provides the linguistic underpinnings of Objective-C. Everything that is true of C is true also of Objective-C. It is possible, and often necessary, to write long stretches of Objective-C code that are, in effect, pure C. Some of the Cocoa APIs are written in C. Therefore, in order to know about Objective-C, it is necessary to know about C.

The C language was evolved during the early 1970s at Bell Labs in conjunction with the creation of Unix. The reference manual, The C Language by Brian Kernighan and Dennis M. Ritchie, was published in 1978, and remains one of the best computer books ever written.

C statements, including declarations, must end in a semicolon. Variables must be declared before use. A variable declaration consists of a data type name followed by the variable name, optionally followed by assignment of an initial value:

int i;
double d = 3.14159;

The C typedef statement starts with an existing type name and defines a new synonym for it:

typedef double NSTimeInterval;

C Data Types

C is not an object-oriented language; its data types are not objects (they are scalars). The basic built-in C data types are all numeric: char (one byte), int (four bytes), float and double (floating-point numbers), and varieties such as short (short integer), long (long integer), unsigned short, and so on. Objective-C adds NSInteger, NSUInteger (unsigned), and CGFloat. The C bool type is actually a numeric, with zero representing false; Objective-C adds BOOL, which is also a numeric. Even the C native text type (string) is actually a null-terminated array of char, and I’ll discuss it later.

Swift supplies numeric types that interface directly with C numeric types, even though Swift’s types are objects and C’s types are not. Swift type aliases provide names that correspond to the C type names: a Swift CBool (Bool) is a C bool, a Swift CChar (Int8) is a C char, a Swift CInt (Int32) is a C int, a Swift CFloat (Float) is a C float, and so on. Swift Int interchanges with NSInteger; Swift UInt interchanges with NSUInteger. CGFloat is adopted as a Swift type name. Swift ObjCBool represents Objective-C BOOL, but it is not a Bool; to derive the Bool, take its boolValue. (You can, however, assign a Swift Bool literal where an ObjCBool is expected, because ObjCBool adopts ExpressibleByBooleanLiteral.)

A major difference between C and Swift is that C (and therefore Objective-C) implicitly coerces when values of different numeric types are assigned, passed, compared to, or combined with one another; Swift doesn’t, so you must coerce explicitly to make types match exactly, as I described in Chapter 3.

C Enums

A C enum is numeric; values are some sort of integer, and can be implicit (starting from 0) or explicit. Enums arrive in various forms into Swift, depending on how they are declared.

Old-fashioned C enum

This is the simplest and oldest form:

enum State {
    kDead,
    kAlive
};
typedef enum State State;

(The typedef in the last line merely allows C programs to use the term State as the name of this type instead of the more verbose enum State.) In C, the enumerand names kDead and kAlive are not “cases” of anything; they are not namespaced. They are constants, and as they are not explicitly initialized, they represent 0 and 1 respectively. An enum declaration can specify the integer type further; this one doesn’t, so the values are typed in Swift as UInt32.

This old-fashioned sort of C enum arrives as a Swift struct adopting the RawRepresentable protocol, and its enumerands (here, kDead and kAlive) arrive into Swift as synonyms for instances of the State struct with an appropriate rawValue (here, 0 and 1 respectively). The result is that you can use the enumerand names as a medium of interchange wherever a State enum arrives from or is expected by C. If a C function setState takes a State enum parameter, you can call it with one of the State enumerand names:

setState(kDead)

Observe that there are no namespaces in this story! The enumerands are bare names, not members of the State struct; you say kDead, not State.kDead. If you are curious about what integer is represented by the name kDead, you have to take its rawValue. You can also create an arbitrary State value by calling its init(rawValue:) initializer — there is no check to see whether this value is one of the defined constants. But you aren’t expected to do either of those things.

NS_ENUM

Starting back in Xcode 4.4, a C enum notation was introduced that uses the NS_ENUM macro:

typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
    UIStatusBarAnimationNone,
    UIStatusBarAnimationFade,
    UIStatusBarAnimationSlide,
};

That notation both specifies the integer type and associates a type name with this enum as a whole. Swift imports an enum declared this way as a Swift enum with the name and raw value type intact; the enumerand names become namespaced case names, with the common prefix subtracted:

enum UIStatusBarAnimation : Int {
    case none
    case fade
    case slide
}

Going the other way, a Swift enum with an Int raw value type can be exposed to Objective-C using the @objc attribute:

@objc enum Star : Int {
    case blue
    case white
    case yellow
    case red
}

Objective-C sees that as an enum with type NSInteger and enumerand names StarBlue, StarWhite, and so on.

In the special case where the NSENUM type name ends in Error, it arrives into Swift as a struct conforming to Error. Here’s the start of an enum declaration from the Core Location framework:

typedef NS_ENUM(NSInteger, CLError) {
    kCLErrorLocationUnknown = 0,
    kCLErrorDenied,
    kCLErrorNetwork,
    // ...
};

The result is that when Objective-C throws an NSError whose domain is kCLErrorDomain and whose code is kCLErrorLocationUnknown, Swift can catch it by saying catch CLError.locationUnknown.

A knotty problem arises when you write a Swift switch statement that exhausts a C enum tag’s cases. What if, in a future release, the C code is changed to add a case to this enum? If that happens, and if your “exhaustive” switch receives an unknown case, you’ll crash. But Swift is ready with a solution:

  • When you compile your code, you’ll be warned by the compiler that this enum “may have additional unknown values.” To remove the warning, you add a default case. Normally, the compiler would warn you that your default case will never be executed, because your switch is exhaustive; but in this situation, your switch might not be exhaustive some day, so that warning doesn’t appear.

  • In addition, you mark the default case with the @unknown attribute. This tells the compiler that you think your switch is exhaustive (without the default), and you’d like to be warned if it isn’t. If your switch isn’t exhaustive, you’ll get the warning now; if some day a new case is added to the enum, you’ll get the warning then, and you can silence it by adding the new case to your switch.

Let’s demonstrate. Here’s a C enum:

typedef NS_ENUM(NSInteger, TestEnum) {
    TestEnumOne
    TestEnumTwo
};

This arrives into Swift as an enum called TestEnum. Here’s an exhaustive switch over a TestEnum:

switch test { // test is a TestEnum
case .one : break
case .two : break
} // compiler warns

We get a warning from the compiler. Our switch looks exhaustive, but in the future it might not be. So we add an @unknown default case, and the warning goes away:

switch test { // test is a TestEnum
case .one : break
case .two : break
@unknown default: break
}

Suppose the C enum later acquires another case (case .three). No problem! Our Swift switch is crash-proof, because there’s a default case. Even better, when we compile against the C code, our Swift switch will get another warning, telling us that the switch is no longer exhaustive.

If the Objective-C code is our own, and if we’re sure that the C enum will never acquire a new case, we can mark it with NS_CLOSED_ENUM instead of NS_ENUM; this will cause Swift to treat TestEnum like an ordinary Swift enum.

Tip

Some enums in the Swift standard library and Foundation overlays are marked as open to future additional cases in the same way as NS_ENUM.

NS_OPTIONS

Another variant of C enum notation, using the NS_OPTIONS macro, is suitable for bitmasks:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

An enum declared like that arrives into Swift as a struct adopting the OptionSet protocol. The OptionSet protocol adopts the RawRepresentable protocol, so this is a struct with a rawValue instance property holding the underlying integer. The C enum case names are represented by static properties, each of whose values is an instance of this struct; the names of these static properties are imported with the common prefix subtracted. Starting in Swift 4.2, this particular struct is namespaced by nesting it into the UIView class as UIView.AutoresizingMask:

struct AutoresizingMask : OptionSet {
    init(rawValue: UInt)
    static var flexibleLeftMargin: UIView.AutoresizingMask { get }
    static var flexibleWidth: UIView.AutoresizingMask { get }
    static var flexibleRightMargin: UIView.AutoresizingMask { get }
    static var flexibleTopMargin: UIView.AutoresizingMask { get }
    static var flexibleHeight: UIView.AutoresizingMask { get }
    static var flexibleBottomMargin: UIView.AutoresizingMask { get }
}

When you say something like UIView.AutoresizingMask.flexibleLeftMargin, it looks as if you are initializing a case of a Swift enum, but in fact this is an instance of the UIView.AutoresizingMask struct, whose rawValue property has been set to the value declared by the original C enum — which, for .flexibleLeftMargin, is 1<<0. Because a static property of this struct is an instance of the same struct, you can, as I explained in “Inference of Type Name with Static/Class Members”, omit the struct name when supplying a static property name where the struct is expected:

self.view.autoresizingMask = .flexibleWidth

Because this is an OptionSet struct, you can represent and manipulate the bitmask as if it were a Set:

self.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Tip

In Objective-C, where an NS_OPTIONS enum is expected, you pass 0 to indicate that no options are provided. In Swift, where a corresponding struct is expected, you pass [] (an empty set) or omit the options: parameter entirely. Some NS_OPTIONS enums have an explicit option that means 0; Swift sometimes won’t bother to import its name, because passing [] means the same thing. To set a UIView.AutoresizingMask value to UIViewAutoresizingNone in Swift, set it to [] (not .none).

Global string constants

The names of many Objective-C global string constants (referred to jokingly by Apple as stringly typed) are namespaced by importing them into Swift as static struct properties. This is accomplished by means of the NS_STRING_ENUM and NS_EXTENSIBLE_STRING_ENUM Objective-C macros. For example, the names of the NSAttributedString attribute keys used to be simple global string constants (type NSString*):

NSString* const NSFontAttributeName;
NSString* const NSParagraphStyleAttributeName;
NSString* const NSForegroundColorAttributeName;
// ... and so on ...

This meant that they were global string constants in Swift as well. Now, however, they are typed as NSAttributedStringKey values:

NSAttributedStringKey const NSFontAttributeName;
NSAttributedStringKey const NSParagraphStyleAttributeName;
NSAttributedStringKey const NSForegroundColorAttributeName;
// ... and so on ...

NSAttributedStringKey, in Objective-C, is just a synonym for NSString, but it is marked with the NS_EXTENSIBLE_STRING_ENUM macro:

typedef NSString * NSAttributedStringKey NS_EXTENSIBLE_STRING_ENUM;

The result is that these names are imported into Swift as namespaced static properties of an NSAttributedString.Key struct with names like .name, .paragraphStyle, and so on. Moreover, a dictionary that expects these keys has a key type of NSAttributedString.Key, so you can write compact code like this:

self.navigationController?.navigationBar.titleTextAttributes = [
    .font: UIFont(name: "ChalkboardSE-Bold", size: 20)!,
    .foregroundColor: UIColor.darkText
]

C Structs

A C struct is a compound type whose elements can be accessed by name using dot-notation after a reference to the struct:

struct CGPoint {
   CGFloat x;
   CGFloat y;
};
typedef struct CGPoint CGPoint;

After that declaration, it becomes possible to talk like this in C:

CGPoint p;
p.x = 100;
p.y = 200;

A C struct arrives wholesale into Swift as a Swift struct, which is thereupon endowed with Swift struct features. CGPoint in Swift has CGFloat instance properties x and y, but it also magically acquires the implicit memberwise initializer! In addition, a zeroing initializer with no parameters is injected; saying CGPoint() makes a CGPoint whose x and y are both 0. Extensions can supply additional features, and the Swift CoreGraphics header adds a few to CGPoint:

extension CGPoint {
    static var zero: CGPoint { get }
    init(x: Int, y: Int)
    init(x: Double, y: Double)
}

As you can see, a Swift CGPoint has additional initializers accepting Int or Double arguments, along with another way of making a zero CGPoint, CGPoint.zero. CGSize is treated similarly. CGRect is particularly well endowed with added methods and properties in Swift.

The fact that a Swift struct is an object, while a C struct is not, does not pose any problems of communication. You can assign or pass a Swift CGPoint where a C CGPoint is expected, because CGPoint came from C in the first place. The fact that Swift has endowed CGPoint with object methods and properties doesn’t matter; C doesn’t see them. All C cares about are the x and y elements of this CGPoint, which are communicated from Swift to C without difficulty.

C Pointers

A C pointer is an integer designating the location in memory (the address) where the real data resides. Allocating and disposing of that memory is a separate matter. The declaration for a pointer to a data type is written with an asterisk after the data type name; a space can appear on either or both sides of the asterisk. These are equivalent declarations of a pointer-to-int:

int *intPtr1;
int* intPtr2;
int * intPtr3;

The type name itself is int* (or, with a space, int *). Objective-C, for reasons that I’ll explain later, uses C pointers heavily, so you’re going to be seeing that asterisk a lot if you look at any Objective-C.

A C pointer arrives into Swift as an UnsafePointer or, if writable, an UnsafeMutablePointer; this is a generic, and is specified to the actual type of data pointed to. (A pointer is “unsafe” because Swift isn’t managing the memory for, and can’t even guarantee the integrity of, what is pointed to.)

To illustrate, here’s an Objective-C UIColor method declaration; I haven’t discussed this syntax yet, but just concentrate on the types in parentheses:

- (BOOL) getRed: (CGFloat *) red
    green: (CGFloat *) green
    blue: (CGFloat *) blue
    alpha: (CGFloat *) alpha;

CGFloat is a basic numeric type. The type CGFloat * states (despite the space) that these parameters are all CGFloat* — that is, pointer-to-CGFloat.

The Swift translation of that declaration looks, in effect, like this:

func getRed(_ red: UnsafeMutablePointer<CGFloat>,
    green: UnsafeMutablePointer<CGFloat>,
    blue: UnsafeMutablePointer<CGFloat>,
    alpha: UnsafeMutablePointer<CGFloat>) -> Bool

UnsafeMutablePointer in this context is used like a Swift inout parameter: you declare and initialize a var of the appropriate type beforehand, and then pass its address as argument by way of the & prefix operator. When you pass the address of a reference in this way, you are in fact creating and passing a pointer:

var r : CGFloat = 0
var g : CGFloat = 0
var b : CGFloat = 0
var a : CGFloat = 0
c.getRed(&r, green: &g, blue: &b, alpha: &a)

It’s fine to take the address of a variable reference and hand it to a C function that returns immediately, as we are doing here; but do not persist such an address yourself. If r is a CGFloat, saying let rPtr = &r would be a really bad idea; the compiler will warn, and in future this warning is slated to be promoted to be an error. If you need to do that sort of thing, call some form of withUnsafePointer, which takes an anonymous function within which the pointer is valid.

In C, to access the memory pointed to by a pointer, you use an asterisk before the pointer’s name: *intPtr is “the thing pointed to by the pointer intPtr.” In Swift, you use the pointer’s pointee property. In this example, we receive a stop parameter typed originally as a BOOL*, a pointer-to-BOOL; in Swift, it’s an UnsafeMutablePointer<ObjCBool>. To set the BOOL at the far end of this pointer, we set the pointer’s pointee:

// mas is an NSMutableAttributedString, r is an NSRange, f is a UIFont
mas.enumerateAttribute(.font, in: r) { value, r, stop in
    if let value = value as? UIFont, value == f  {
        // ...
        stop.pointee = true // Bool literal assigned to ObjCBool via pointer
    }
}

The most general type of C pointer is pointer-to-void (void*), also known as the generic pointer. The term void here means that no type is specified; it is legal in C to use a generic pointer wherever a specific type of pointer is expected, and vice versa. In effect, pointer-to-void casts away type checking as to what’s at the far end of the pointer. This will appear in Swift as a “raw” pointer, either UnsafeRawPointer or UnsafeMutableRawPointer.

Raw pointers are even more unsafe than normal pointers; not only the lifetime and extent of the memory pointed to, but also the type of what’s in that memory, is now your responsibility. As far as the pointer is concerned, what the memory contains is just bytes. You can cast a typed unsafe pointer to a raw unsafe pointer, but not the other way. Instead, starting with a raw pointer, you can load an object from an address within the memory, or you can bind the memory to derive a typed pointer to the same memory:

// buff is a CVImageBuffer
if let baseAddress = CVPixelBufferGetBaseAddress(buff) {
    // baseAddress is an UnsafeMutableRawPointer
    let addrptr = baseAddress.assumingMemoryBound(to: UInt8.self) // *
    // addrptr is an UnsafeMutablePointer<UInt8>
    // ...
}

C Arrays

A C array contains a fixed number of elements of a single data type. Under the hood, it is a contiguous block of memory sized to accommodate this number of elements of this data type. For this reason, the name of an array in C is the name of a pointer to the first element of the array. If arr has been declared as an array of int, the term arr can be used wherever a value of type int* (a pointer-to-int) is expected. The C language will indicate an array type either by appending square brackets to a reference or as a pointer.

For example, the C function CGContextStrokeLineSegments is declared like this:

void CGContextStrokeLineSegments(CGContextRef c,
   const CGPoint points[],
   size_t count
);

The square brackets in the second line tell you that the second parameter is a C array of CGPoints. A C array carries no information about how many elements it contains, so to pass this C array to this function, you must also tell the function how many elements the array contains; that’s what the third parameter is for. A C array of CGPoint is a pointer to a CGPoint, so this function’s declaration is translated into Swift like this:

func __strokeLineSegments(
    between points: UnsafePointer<CGPoint>?,
    count: Int)

Now, you’re not really expected to call that function. The CGContext Swift overlay provides a pure Swift version, strokeLineSegments, which takes a Swift array of CGPoint with no need to provide a count; and the original CGContextStrokeLineSegments has been marked NS_REFINED_FOR_SWIFT to generate the two underscores and hide it from you. But let’s say you wanted to call __strokeLineSegments anyway. How would you do it?

To call __strokeLineSegments and pass it a C array of CGPoints, it would appear that you need to make a C array of CGPoints. A C array is not, by any stretch of the imagination, a Swift array; so how on earth will you do this? Surprise! You don’t have to. Even though a Swift array is not a C array, you can pass a pointer to a Swift array here. In this example, you don’t even need to pass a pointer; you can pass a reference to a Swift array itself. And since this is not a mutable pointer, you can declare the array with let; indeed, you can even pass a Swift array literal! No matter which approach you choose, Swift will convert to a C array for you as the argument crosses the bridge from Swift to C:

let c = UIGraphicsGetCurrentContext()!
let arr = [
    CGPoint(x:0,y:0),
    CGPoint(x:50,y:50),
    CGPoint(x:50,y:50),
    CGPoint(x:0,y:100),
]
c.__strokeLineSegments(between: arr, count: arr.count)

However, you can form a C array if you really want to. This is where the “Unsafe” in an unsafe pointer really comes into play: you must manage the memory yourself, explicitly, and getting it right is entirely up to you. First, you set aside the block of memory by declaring an UnsafeMutablePointer of the desired type and calling the class method allocate(capacity:) with the desired number of elements. Then you populate (technically, initialize) that memory. You will also be responsible for undoing all of that later; you deinitialize the memory and deallocate it. The best way to ensure that is to configure the block of memory and then immediately complete the memory management in a defer block:

let ptr = UnsafeMutablePointer<CGPoint>.allocate(capacity:4)
ptr.initialize(repeating: .zero, count: 4)
defer {
    ptr.deinitialize(count:4)
    ptr.deallocate()
}

Now that memory management is configured, you can manipulate the element values. In this instance, we want to write real CGPoint values into the memory block. You could do this by manipulating the pointee, but you can also use subscripting, which might be a lot more convenient. Be careful to stay within the block of memory you have configured! There’s no range checking, and writing outside memory you own can mysteriously wreck your program later:

ptr[0] = CGPoint(x:0,y:0)
ptr[1] = CGPoint(x:50,y:50)
ptr[2] = CGPoint(x:50,y:50)
ptr[3] = CGPoint(x:0,y:100)

Finally, since the UnsafeMutablePointer is a pointer, you pass it, not a pointer to it, as argument:

let c = UIGraphicsGetCurrentContext()!
c.__strokeLineSegments(between: ptr, count: 4)

The same convenient subscripting is available when you receive a C array. In this example, col is a UIColor; comp is typed as an UnsafePointer to CGFloat. That is really a C array of CGFloat, and so you can access its elements by subscripting:

if let comp = col.cgColor.__unsafeComponents,
    let sp = col.cgColor.colorSpace,
    sp.model == .rgb {
        let red = comp[0]
        let green = comp[1]
        let blue = comp[2]
        let alpha = comp[3]
        // ...
}

C Strings

The native C string type is not a distinct type; it is a null-terminated array of char. Therefore it may be typed in Swift as [Int8] or [CChar], because CChar is Int8, or as UnsafePointer<Int8> or UnsafePointer<CChar>, because a C array is a pointer to the first element of the array. These representations are effectively interchangeable.

A C string can’t be formed as a literal in Swift, but you can pass a Swift String where a C string is expected; in this example, takeCString is a C function that takes a C string:

let s = "hello"
takeCString("hello")
takeCString(s)

If you have to, you can form a real C string in Swift. The Swift Foundation overlay provides the cString(using:) method:

let arrayOfCChar : [CChar]? = s.cString(using: .utf8)
takeCString(arrayOfCChar!)

Swift String provides the utf8CString property, a ContiguousArray<CChar>; you can turn that into a pointer with the withUnsafeBufferPointer method:

let contiguousArrayOfCChar : ContiguousArray<CChar> = s.utf8CString
contiguousArrayOfCChar.withUnsafeBufferPointer { (ptr) -> Void in
    takeCString(ptr.baseAddress!)
}

More simply, you can call the String withCString method:

s.withCString { (ptr) -> Void in
    takeCString(ptr)
}

In the other direction, a UTF-8 C string can be rendered into a Swift String by way of a Swift String initializer such as init(cString:) or init?(validatingUTF8:). To specify some other encoding, call the static method decodeCString(_:as:). In this example, returnCString is a C function that returns a C string:

let result : UnsafePointer<Int8> = returnCString()
let resultString : String = String(cString: result)

C Functions

A C function declaration starts with the return type (which might be void, meaning no returned value), followed by the function name, followed by a parameter list — parentheses containing comma-separated pairs consisting of the type followed by the parameter name. The parameter names are purely internal. C functions are global, and Swift can call them directly.

Here’s the C declaration for an Audio Services function:

OSStatus AudioServicesCreateSystemSoundID(
    CFURLRef inFileURL,
    SystemSoundID* outSystemSoundID)

An OSStatus is basically an Int32. A CFURLRef is a CFTypeRef (“Memory Management of CFTypeRefs”) and is called CFURL in Swift. A SystemSoundID is a UInt32, and the * makes this a C pointer, as we already know. The whole thing translates directly into Swift:

func AudioServicesCreateSystemSoundID(
    _ inFileURL: CFURL,
    _ outSystemSoundID: UnsafeMutablePointer<SystemSoundID>) -> OSStatus

CFURL is (for reasons that I’ll explain later) interchangeable with NSURL and Swift URL; so here we are, calling this C function in Swift:

let sndurl = Bundle.main.url(forResource: "test", withExtension: "aif")!
var snd : SystemSoundID = 0
AudioServicesCreateSystemSoundID(sndurl as CFURL, &snd)

Struct functions

Most of the commonly used C global functions in Cocoa operate on a struct; they have the name of that struct as the first element of their name, and have that struct itself as their first parameter. In Swift, where structs are objects, these functions are often transformed into methods on the struct.

For example, in Objective-C, the way to construct a CGRect from scratch is with the CGRectMake function, and the way to divide a CGRect is with the CGRectDivide function:

CGRect rect = CGRectMake(10,10,100,100);
CGRect arrow;
CGRect body;
CGRectDivide(rect, &arrow, &body, arrowHeight, CGRectMinYEdge);

In Swift, CGRectMake is overshadowed by the CGRect struct initializer init(x:y:width:height:), and CGRectDivide is overshadowed by the CGRect divided method:

let rect = CGRect(x: 10, y: 10, width: 100, height: 100)
let (arrow, body) = rect.divided(atDistance: arrowHeight, from: .minYEdge)

Pointer-to-function

In C, a function has a type based on its signature, and the name of a function is a reference to the function, and so it is possible to pass a function — sometimes termed a pointer-to-function — by using the function’s name where a function of that type is expected.

Here’s the declaration for a C function from the Audio Toolbox framework:

OSStatus AudioServicesAddSystemSoundCompletion(SystemSoundID inSystemSoundID,
    CFRunLoopRef __nullable inRunLoop,
    CFStringRef __nullable inRunLoopMode,
    AudioServicesSystemSoundCompletionProc inCompletionRoutine,
    void * __nullable inClientData)

(I’ll explain the term __nullable later.) What’s an AudioServicesSystemSoundCompletionProc? Here’s how it’s declared:

typedef void (*AudioServicesSystemSoundCompletionProc)(
    SystemSoundID ssID,
    void* __nullable clientData);

In the first line, the asterisk and name in parentheses means that this is the name of a pointer-to-function. A SystemSoundID is a UInt32. So this declaration means that an AudioServicesSystemSoundCompletionProc is a pointer to a function taking two parameters (typed UInt32 and pointer-to-void) and returning no result.

Amazingly, you can pass a Swift function where a C pointer-to-function is expected! As always when passing a function, you can define the function separately and pass its name, or you can form the function inline as an anonymous function. If you’re going to define the function separately, it cannot be a method. A function defined at the top level of a file is fine; so is a function defined locally within a function.

So here’s my AudioServicesSystemSoundCompletionProc, declared at the top level of a file:

func soundFinished(_ snd:UInt32, _ c:UnsafeMutableRawPointer?) {
    AudioServicesRemoveSystemSoundCompletion(snd)
    AudioServicesDisposeSystemSoundID(snd)
}

And here’s my code for playing a sound file as a system sound, including a call to AudioServicesAddSystemSoundCompletion:

let sndurl = Bundle.main.url(forResource: "test", withExtension: "aif")!
var snd : SystemSoundID = 0
AudioServicesCreateSystemSoundID(sndurl as CFURL, &snd)
AudioServicesAddSystemSoundCompletion(snd, nil, nil, soundFinished, nil)
AudioServicesPlaySystemSound(snd)

Objective-C

Objective-C is built on top of C. It adds some syntax and features, but it continues at the same time to use C syntax and data types, and remains C under the hood.

The Objective-C language was created by Brad Cox and Tom Love in the early 1980s to furnish C with the object-oriented capabilities of Smalltalk. Its adoption by NeXT, under the leadership of Steve Jobs, drove the evolution toward the mature form of the language during the late 1980s, spearheaded by Steve Naroff. In 1997, when Jobs had returned to Apple and Apple acquired NeXT, Objective-C became the language of Mac OS X Cocoa. Cocoa Touch, created for the iPhone a decade later, still uses Objective-C; that’s why your use of Swift in programming iOS and UIKit depends upon Swift’s interoperability with Objective-C.

Unlike Swift, Objective-C has no namespaces. For this reason, different frameworks distinguish their contents by starting the names of types, functions, and constants with distinct prefixes. The “CG” in “CGFloat” stands for Core Graphics, because it is declared in the Core Graphics framework. The “NS” in “NSString” stands for NeXTStep, the framework that later became Cocoa.

Objective-C Objects and C Pointers

All the data types and syntax of C are part of Objective-C. But Objective-C is object-oriented, so it needs a way of adding objects to C. It does this by taking advantage of C pointers. C pointers accommodate having anything at all at the far end of the pointer; management of whatever is pointed to is a separate matter, and that’s just what Objective-C takes care of. Objective-C object types are expressed using C pointer syntax.

Here’s the Objective-C declaration for the addSubview: method:

- (void)addSubview:(UIView *)view;

I haven’t discussed Objective-C method declaration syntax yet, but focus on the type declaration for the view parameter, in parentheses: it is UIView*. This appears to mean “a pointer to a UIView.” It does mean that — and it doesn’t. What’s at the far end of the pointer is certainly a UIView instance. But all Objective-C object references are pointers. The fact that this is a pointer is merely a consequence of the fact that it’s an object.

The Swift translation of this method declaration doesn’t appear to involve any pointers:

func addSubview(_ view: UIView)

In general, in Swift, you will simply pass a reference to a class instance where Objective-C expects a class instance; the asterisk used in Objective-C to express the fact that this is an object won’t matter. What you pass as argument when calling addSubview(_:) from Swift is a UIView instance — which is exactly what Objective-C expects. There is, of course, a sense in which you are passing a pointer when you pass a class instance — because classes are reference types! A class instance is actually seen the same way by both Swift and Objective-C; the difference is that Swift doesn’t use pointer notation.

Objective-C’s id type is a general pointer to an object — the object equivalent of C pointer-to-void. Any object type can be assigned or cast to or from an id. Because id is itself a pointer, a reference declared as id doesn’t use an asterisk; it is rare (though not impossible) to encounter an id*.

Objective-C Objects and Swift Objects

Objective-C objects are classes and instances of classes. They arrive into Swift more or less intact. You won’t have any trouble subclassing Objective-C classes or working with instances of Objective-C classes. (For how Swift sees Objective-C properties and accessors, see Chapter 10.)

Going the other way, when Objective-C expects an object, it expects a class or an instance of a class, and Swift can provide it. But what Objective-C means by a class, in general, is a subclass of NSObject. Every other kind of object known to Swift has to be bridged or boxed in order to survive the journey into Objective-C’s world. Moreover, many features of Swift are meaningless to Objective-C, and those features are invisible to Objective-C. Objective-C can’t see any of the following:

  • Swift enums, except for an @objc enum with an Int raw value

  • Swift structs, except for structs that come ultimately from C or that are bridged to Objective-C classes

  • Swift classes not derived from NSObject

  • Swift protocols not marked @objc

  • Protocol extensions

  • Generics

  • Tuples

  • Nested types

Nothing in that list can be directly exposed to Objective-C — and, by implication, nothing that involves anything in that list can be exposed to Objective-C. Suppose we have a class MyClass not derived from NSObject. Then if your UIViewController subclass has a property typed as MyClass, that property cannot be exposed to Objective-C; and if your UIViewController subclass has a method that receives or returns a value typed as MyClass, that method cannot be exposed to Objective-C.

Nevertheless, you are perfectly free to use such properties and methods, even in a class (such as a UIViewController subclass) that is exposed to Objective-C. Objective-C simply won’t be able to see those aspects of the class that would be meaningless to it.

Exposure of Swift to Objective-C

Starting in Swift 4, invisibility of Swift code to Objective-C is the norm. With a few exceptions, even if Objective-C can theoretically see a thing, it won’t see it unless you explicitly expose it to Objective-C. You do that with the @objc attribute.

Let’s talk first about the exceptions. These are things in your Swift code that Objective-C will be able to see automatically, without an explicit @objc attribute:

  • A class derived from NSObject. Such a class will be declared in Swift either as subclassing NSObject itself or as subclassing some NSObject subclass, typically a class defined by Cocoa (such as UIViewController).

  • Within such a class, an override of a method defined in Objective-C (such as UIViewController’s viewDidLoad) or defined in Swift but marked @objc.

  • Within such a class, an implementation of a member of a protocol adopted by the class, if the protocol is defined in Objective-C (such as NSCoding’s init(coder:)) or defined in Swift but marked @objc.

  • Within such a class, an instance property marked @IBOutlet or @IBInspectable or @NSManaged, or a method marked @IBAction (see Chapter 7).

Otherwise, to expose to Objective-C a property, method, or protocol, mark it with @objc. The compiler will stop you if you try to expose to Objective-C something that it is unable to see (such as a property whose type Objective-C cannot see or cannot understand). A protocol marked as @objc automatically becomes a class protocol.

A useful trick, if you have several methods that you need to expose explicitly to Objective-C, is to clump them into an extension that is itself marked @objc; there is then no need to mark those methods with @objc individually. If most or all of a class’s members are to be exposed to Objective-C, you can mark the class @objcMembers; again, there is then no need to mark those members with @objc individually. Conversely, if a class member would be exposed to Objective-C and you want to prevent this, you can mark it @nonobjc.

There are two additional uses of @objc:

Expose a member of a nonObjective-C class

Even if a class is not exposed to Objective-C, it can be useful to mark a member of that class with @objc so that your Swift code can take advantage of Objective-C language features with regard to that member. A Timer using the target–action pattern (Chapter 11) can have a method of a nonObjective-C class as its action, but only if that method is marked @objc, because the method is specified with a selector (Chapter 2) and selectors are an Objective-C feature.

Change the Objective-C name of something

When you mark something with @objc, you can add parentheses containing the name by which you want Objective-C to see this thing. You are free to do this even for a class or a class member that Objective-C can see already. An example appeared in Chapter 10 when I changed the name by which Objective-C sees a property accessor. When using this feature, you bypass Swift’s behind-the-scenes name mangling designed to prevent clashes with any existing Objective-C names, so you must take responsibility for avoiding such a clash yourself.

Tip

Class members marked @objc, @IBAction, and @IBOutlet can be marked private to speed up compilation and reduce the footprint of the class’s exposure to Objective-C. However, as I mentioned in Chapter 5, you shouldn’t do that with an implementation of an optional member of an adopted Objective-C protocol.

Bridged Types and Boxed Types

Swift will convert certain native nonclass types to their Objective-C class equivalents for you. The following native Swift structs are bridged to Objective-C class types:

  • String to NSString

  • Numbers (and Bool) to NSNumber

  • Array to NSArray

  • Dictionary to NSDictionary

  • Set to NSSet

Bridging has two immediate practical consequences for your code:

Parameter passing

You can pass an instance of the Swift struct where the Objective-C class is expected. In fact, in general you’ll rarely even encounter the Objective-C class, because the Swift rendering of the API will display it as the Swift struct: if an Objective-C method takes an NSString, you’ll see it in Swift as taking a String, and so on.

Casting

You can cast between the Swift struct and the Objective-C class. When casting from Swift to Objective-C, this is not a downcast, so the bare as operator is all you need. But casting from Objective-C to Swift, except for NSString to String, involves adding type information — NSNumber wraps some specific numeric type, and the collection types contain elements of some specific type — so you might need to cast down with as! or as? in order to specify that type.

Also, certain common Objective-C structs that can easily be wrapped by NSValue in Objective-C are bridged to NSValue in Swift. The common structs are CGPoint, CGSize, CGRect, CGAffineTransform, UIEdgeInsets, UIOffset, NSRange, CATransform3D, CMTime, CMTimeMapping, CMTimeRange, MKCoordinate, and MKCoordinateSpan.

In addition, various Cocoa Foundation classes are overlaid by Swift types whose names are the same but without the “NS” prefix. Often, extra functionality is injected to make the type behave in a more Swift-like way; and, where appropriate, the Swift type may be a struct, allowing you to take advantage of Swift value type semantics. NSMutableData, for instance, becomes otiose, because Data, the overlay for Objective-C NSData, is a struct with mutating methods and can be declared with let or var. And Date, the overlay for Objective-C NSDate, adopts Equatable and Comparable, so that an NSDate method like earlierDate: can be replaced by the min function.

The Swift overlay types are all bridged to their Foundation counterparts. The Swift rendering of an Objective-C API will show you the Swift overlay type rather than the Objective-C type: a Cocoa method that takes or returns an NSDate in Objective-C will take or return a Date in Swift, and so on. If necessary, you can cast between bridged types; for example, you can turn a Date into an NSDate with as.

Objective-C id is rendered as Any in Swift. This means that wherever an Objective-C API accepts an id parameter, that parameter is typed in Swift as Any and can be passed any Swift value whatever. If that value is of a bridged type, the bridge is crossed automatically, just as if you had cast explicitly with as. A String becomes an NSString, an Array becomes an NSArray, a number is wrapped in an NSNumber, a CGPoint or other common struct is wrapped in an NSValue, a Data becomes an NSData, and so forth.

The same rule applies when you pass a Swift collection to Objective-C, with regard to the collection’s elements. If an element is of a bridged type, the bridge is crossed automatically. The typical case in point is when you pass a Swift array to Objective-C: an array of Int becomes an NSArray of NSNumbers; an array of CGPoint becomes an NSArray of NSValues; for an array with an Optional element type, any nil elements become NSNull instances (Chapter 10).

What happens when an object tries to cross the bridge from Swift to Objective-C, but that instance is not of a bridged type? (Such an object might be an enum, a struct of a nonbridged type, or a class that doesn’t derive from NSObject.) On the one hand, Objective-C can’t do anything with this object. On the other hand, the object needs to be allowed to cross the bridge somehow, especially because you, on the Swift side, might ask for the object back again later, and it needs to be returned to you intact.

To illustrate, suppose Person is a struct with a firstName and a lastName property. Then you might need to be able to do something like this:

// lay is a CALayer
let p = Person(firstName: "Matt", lastName: "Neuburg")
lay.setValue(p, forKey: "person")
// ... time passes ...
if let p2 = lay.value(forKey: "person") as? Person {
    print(p2.firstName, p2.lastName) // Matt Neuburg
}

Amazingly, this works. How? The answer, in a nutshell, is that Swift boxes this object into something that Objective-C can see as an object, even though Objective-C can’t do anything with that object other than store and retrieve it. How Swift does this is irrelevant; it’s an implementation detail, and none of your business. It happens that in this case the Person object is wrapped up in a _SwiftValue, but that name is unimportant; what’s important is that it is an Objective-C object, wrapping the value we provided. In this way, Objective-C is able to store the object for us, in its box, and hand it back to us intact upon request. Like Pandora, Objective-C will cope perfectly well as long as it doesn’t look in the box!

Objective-C Methods

In Objective-C, method parameters can (and nearly always do) have external names, and the name of a method as a whole is not distinct from the external names of the parameters: the parameter names are part of the method name, with a colon appearing where each parameter would need to go. Here’s a typical Objective-C method declaration from Cocoa’s NSString class:

- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
                                        withString:(NSString *)replacement

The Objective-C name of that method is:

stringByReplacingOccurrencesOfString:withString:

A declaration for an Objective-C method has three parts:

  • Either + or -, meaning that the method is a class method or an instance method, respectively.

  • The data type of the return value, in parentheses. It might be void, meaning no returned value.

  • The name of the method, split after each colon so as to make room for the parameters. Following each colon is the data type of the parameter, in parentheses, followed by a placeholder (internal) name for the parameter.

Renamification

When Swift calls an Objective-C method, there’s an obvious mismatch between the rules and conventions of the two languages:

Swift method names

A Swift method is a function; the base name of the function is followed by parentheses, and if the function’s parameters have external names (labels), they appear inside the parentheses, like this: swiftFunction(parameter:).

Objective-C method names

An Objective-C method name involves no parentheses and has no separate base name. If the method takes parameters, the parameter names, each followed by a colon, constitute the name of the method; the first thing in the name is just the name of the first parameter. (If it takes no parameters, its name is just its name with no colon.)

To cope with this mismatch, Swift renders the Objective-C method’s name more Swift-like by a process called renamification, which is performed by a component called the Clang importer, mediating between the two languages. The renamification rules are rather elaborate, but you don’t need to know the details; you can get a general sense of how they behave from an example. Here’s how the renamification rules transform the stringByReplacingOccurrencesOfString:withString: method into a Swift function:

  1. Swift prunes redundant initial type names. We’re starting with a string, and it’s obvious from the return type that a string is returned, so there’s no point saying string at the start. We are left with byReplacingOccurrencesOfString:withString:.

  2. Swift prunes initial by. That’s a common Cocoa locution, but Swift finds it merely verbose. Now we’re down to replacingOccurrencesOfString:withString:.

  3. Swift prunes redundant final type names. It’s obvious that the parameters are strings, so there’s no point saying string at the end of the parameter names. That leaves replacingOccurrencesOf:with:.

  4. Finally, Swift decides where to split the first parameter name into the Swift base name and the external first parameter name. Here, Swift sees that the first parameter name now ends with a known preposition, of, so it splits before that preposition.

Here’s the resulting renamification of that method:

func replacingOccurrences(of target:String, with replacement:String)

And here’s an actual example of calling it:

let s = "hello"
let s2 = s.replacingOccurrences(of: "ell", with:"ipp")
// s2 is now "hippo"

If the Objective-C method being renamified belongs to you, you can intervene manually and tell Swift how to renamify this method, by appending NS_SWIFT_NAME(...) to the declaration (before the semicolon), where what’s inside the parentheses is a Swift function reference. Here’s an example:

- (void) triumphOverThing: (Thing*) otherThing NS_SWIFT_NAME(triumph(over:));

The Clang importer would normally renamify that in Swift as:

func triumphOverThing(_ otherThing: Thing)

Presumably that’s because the importer doesn’t understand over as a preposition. But by intervening manually, we’ve told it to use this instead:

func triumph(over otherThing: Thing)

Internal parameter names

When you call an Objective-C method from Swift, Objective-C’s internal names for the parameters don’t matter; you don’t use them, and you don’t need to know or care what they are. The internal names do appear in the Swift declaration of the method, and they might even help you understand what the method does; but they are not involved in the call. This is the Objective-C declaration of a method:

- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
                                        withString:(NSString *)replacement

And this is the Swift translation of that declaration:

func replacingOccurrences(of target:String, with replacement:String)

But the call site looks like this:

let s2 = s.replacingOccurrences(of: "ell", with:"ipp")

When you override an Objective-C method in Swift, code completion will suggest internal names corresponding to the Objective-C internal names, but you are free to change them. Here’s the Objective-C declaration of the UIViewController prepareForSegue:sender: instance method:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender;

When you override that method in your UIViewController subclass, the suggested template, in accordance with the renamification rules, looks like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // ...
}

But the internal names are local variable names for your use inside the function body, and Objective-C doesn’t care about them; so you can change them. This is a valid (but weird) override of prepareForSegue:sender: in Swift:

override func prepare(for war: UIStoryboardSegue, sender bow: Any?) {
    // ...
}

Reverse renamification

Now let’s talk about what happens going the other way: How does Objective-C see methods declared in Swift? The simplest case is when the first parameter has no external name. Here’s a Swift method intended as the action method of a button in the interface:

@IBAction func doButton(_ sender: Any?) {
    // ...
}

That method is seen by Objective-C as doButton:. That is the canonical form for an action method with one parameter, and for that reason I like to declare my action methods along those lines.

If a Swift method’s first parameter does have an external name, then, as seen by Objective-C, that external name is appended to the Swift base name following an inserted preposition with. Here’s a Swift method:

func makeHash(ingredients stuff:[String]) {
    // ...
}

That method is seen by Objective-C as makeHashWithIngredients:.

But if the external name of the first parameter is a preposition, then it is appended directly to the Swift base name. Here’s another Swift method:

func makeHash(of stuff:[String]) {
    // ...
}

That method is seen by Objective-C as makeHashOf:.

Overloading

Unlike Swift, Objective-C does not permit overloading of methods. Two ViewController instance methods called myMethod: returning no result, one taking a CGFloat parameter and one taking an NSString parameter, would be illegal in Objective-C. Therefore, two such Swift methods, though legal as far as Swift is concerned, would be illegal if they were both visible to Objective-C.

So if methods are overloads of one another in Swift, don’t expose more than one of those methods to Objective-C.

Variadics

Objective-C has its own version of a variadic parameter. The NSArray instance method arrayWithObjects: is declared like this:

+ (id)arrayWithObjects:(id)firstObj, ... ;

Unlike Swift, such methods in Objective-C must somehow be told explicitly how many arguments are being supplied. Many such methods, including arrayWithObjects:, use a nil terminator; that is, the caller supplies nil after the last argument, and the callee knows when it has reached the last argument because it encounters nil. A call to arrayWithObjects: in Objective-C would look something like this:

NSArray* pep = [NSArray arrayWithObjects: manny, moe, jack, nil];

Objective-C cannot call (or see) a Swift method that takes a variadic parameter. Swift, however, can call an Objective-C method that takes a variadic parameter, provided it is marked NS_REQUIRES_NIL_TERMINATION. And in fact, arrayWithObjects: is marked in this way, so you can say NSArray(objects:1, 2, 3) and Swift will supply the missing nil terminator.

Initializers and factories

Objective-C initializer methods are instance methods; actual instantiation is performed using the NSObject class method alloc, for which Swift has no equivalent (and doesn’t need one), and the initializer message is sent to the instance that results. Here’s how you create a UIColor instance by supplying red, green, blue, and alpha values in Objective-C:

UIColor* col = [[UIColor alloc] initWithRed:0.5 green:0.6 blue:0.7 alpha:1];

The name of that initializer, in Objective-C, is initWithRed:green:blue:alpha:. It’s declared like this:

- (UIColor *)initWithRed:(CGFloat)red green:(CGFloat)green
    blue:(CGFloat)blue alpha:(CGFloat)alpha;

In short, an initializer method, to all outward appearances, is just an instance method like any other in Objective-C.

Swift, nevertheless, is able to detect that an Objective-C initializer is an initializer, because the name is special — it starts with init! Therefore, Swift is able to translate an Objective-C initializer into a Swift initializer. The word init is stripped from the start of the method name, and the preposition with, if it appears, is stripped as well. What’s left is the external name of the first parameter. Swift translates the Objective-C initializer initWithRed:green:blue:alpha: into the Swift initializer init(red:green:blue:alpha:), which is declared like this:

init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)

And you’d call it like this:

let col = UIColor(red: 0.5, green: 0.6, blue: 0.7, alpha: 1.0)

The same principle operates in reverse: a Swift initializer init(value:) is visible to and callable by Objective-C under the name initWithValue:.

Tip

If you’re in charge of the Objective-C header being imported into Swift, be sure to mark your designated initializers as NS_DESIGNATED_INITIALIZER so that Swift can distinguish them. To block an initializer explicitly from being imported into Swift, mark it NS_UNAVAILABLE.

There is a second way to create an instance in Objective-C. Very commonly, a class will supply a class method that is a factory for instances. For example, the UIColor class has a class factory method colorWithRed:green:blue:alpha:, declared as follows:

+ (UIColor*) colorWithRed: (CGFloat) red green: (CGFloat) green
                     blue: (CGFloat) blue alpha: (CGFloat) alpha;

Swift detects a factory method of this kind by some pattern-matching rules — a class method that returns an instance of the class, and whose name begins with the name of the class, stripped of its prefix — and translates it as an initializer, stripping the class name (and the with) from the start of the first parameter name. If the resulting initializer exists already, as it does in this example, then Swift treats the factory method as superfluous and suppresses it completely! The Objective-C class method colorWithRed:green:blue:alpha: isn’t callable from Swift, because it would be identical to init(red:green:blue:alpha:) which already exists.

Error pointers

There’s a specialized pattern in Objective-C where a method returning a BOOL or an object takes an NSErrorPointer parameter — that is, an NSError**, the Objective-C equivalent of an inout Error. The idea is that if there’s an exception, the method returns false or nil respectively, and sets the NSError parameter by indirection. This is Objective-C’s way of solving the problem that it can return only one value (there are no tuples).

For example, NSString has an initializer declared in Objective-C like this:

- (instancetype)initWithContentsOfFile:(NSString *)path
                              encoding:(NSStringEncoding)enc
                                 error:(NSError **)error;

Objective-C code that calls that initializer must test to see whether the resulting NSString is in fact nil, and can examine the resulting error if it is:

NSError* err;
NSString* s = [[NSString alloc] initWithContentsOfFile:f
                  encoding:NSUTF8StringEncoding
                  error:&err];
if (s == nil) {
    NSLog(@"%@", err);
}

As you can see, the whole procedure really is a lot like using a Swift inout parameter. An NSError variable is prepared beforehand, and its address is passed to the initializer as the error: argument. After the call, we test the initializer’s result for nil explicitly, to see whether the initialization succeeded; if it didn’t, we can examine the NSError variable to see what the error was. This is an annoyingly elaborate but necessary dance in Objective-C.

In Swift, an Objective-C method that takes an NSError** and returns a nullable object or a BOOL is automatically recast to take advantage of the error mechanism. The error: parameter is stripped from the Swift translation of the declaration, and is replaced by a throws marker:

init(contentsOfFile path: String, encoding enc: String.Encoding) throws

If there are no other parameters besides the NSError** and the parameter name ends withError:, those words are stripped to form the base name of the Swift method, which takes no parameters.

If you call a throws method that belongs to Objective-C and the Objective-C method returns nil or false, Swift sees that as a throw and throws the error that the Objective-C method returned by indirection. If the Objective-C method gets the pattern wrong and returns nil or false but forgets to set the NSError, Swift just makes up an error (_GenericObjCError.nilError) and throws it anyway. If the Objective-C method returns a BOOL, Swift portrays it as returning no result, as the presence or absence of an error is dispositive.

The same method bridging works also in reverse: a Swift throws method that is exposed to Objective-C is seen as taking an NSError** parameter.

Selectors

A Cocoa Objective-C method will sometimes expect as parameter the name of a method that Cocoa is to call later. Such a name is called a selector. For example, the Objective-C UIControl addTarget:action:forControlEvents: method can be called as a way of telling a button in the interface, “From now on, whenever you are tapped, send this message to this object.” The object is the target: parameter. The message, the action: parameter, is a selector. The target object implements this method; Cocoa will call this method on the target object.

You may imagine that, if this were a Swift method, you’d be passing a function here. But a selector is not the same as a function. It’s just a name. Objective-C, unlike Swift, is so dynamic that it is able at runtime to construct and send an arbitrary message to an arbitrary object based on the name alone. Still, a selector is not exactly a string, either; it’s a separate object type, designated in Objective-C declarations as SEL and in Swift declarations as Selector.

You can create a Selector by calling the Selector initializer, which takes a string. In the following examples, b is a UIButton:

b.addTarget(self, action: Selector("doNewGame:"), for: .touchUpInside)

As a shorthand, you can even pass a string literal where a Selector is expected, even though a Selector is not a string:

b.addTarget(self, action: "doNewGame:", for: .touchUpInside)

But don’t do either of those things! Forming a literal selector string by hand is an invitation to form the string incorrectly, resulting in a selector that at best will fail to work, and at worst will cause your app to crash. Swift solves this problem by providing #selector syntax (described in Chapter 2):

b.addTarget(self, action: #selector(doNewGame), for: .touchUpInside)

The use of #selector syntax has numerous advantages. In addition to translating the method name to a selector for you, the compiler can check for the existence of the method in question, and can stop you from telling Objective-C to use a selector to call a method that isn’t exposed to Objective-C (which would cause a crash at runtime).

Indeed, #selector syntax means that you will probably never need to form a selector from a string! Nevertheless, you can do so if you really want to. The rules for deriving an Objective-C name string from a Swift method name are completely mechanical:

  1. The string starts with everything that precedes the left parenthesis in the method name (the base name).

  2. If the method takes no parameters, stop. That’s the end of the string.

  3. If the method’s first parameter has an external parameter name, append With and a capitalized version of that name, unless it is a preposition, in which case append a capitalized version of it directly.

  4. Add a colon.

  5. If the method takes exactly one parameter, stop. That’s the end of the string.

  6. If the method takes more than one parameter, add the external names of all remaining parameters, with a colon after each external parameter name.

Observe that this means that if the method takes any parameters, its Objective-C name string will end with a colon. Capitalization counts, and the name should contain no spaces or other punctuation except for the colons.

To illustrate, here are some Swift method declarations, with their Objective-C name strings given in a comment:

func sayHello() -> String         // "sayHello"
func say(_ s:String)              // "say:"
func say(string s:String)         // "sayWithString:"
func say(of s:String)             // "sayOf:"
func say(_ s:String, times n:Int) // "say:times:"

CFTypeRefs

A CFTypeRef is a pointer to an opaque struct that acts as a pseudo-object. (I talked about CFTypeRef pseudo-objects and their memory management in Chapter 12.) CFTypeRef functions are global C functions. Swift can call C functions, and before Swift 3 introduced renamification, CFTypeRef code looked almost as if Swift were C:

// before Swift 3:
let con = UIGraphicsGetCurrentContext()!
let sp = CGColorSpaceCreateDeviceGray()
// ... colors and locs are arrays of CGFloat ...
let grad = CGGradientCreateWithColorComponents (sp, colors, locs, 3)
CGContextDrawLinearGradient (
    con, grad, CGPointMake(89,0), CGPointMake(111,0), [])

Notice that the “subject” of each function call appears at the start of the name:

  • CGColorSpaceCreateDeviceGray creates a CGColorSpace pseudo-object.

  • CGGradientCreateWithColorComponents creates a CGGradient pseudo-object; the first parameter is the CGColorSpace pseudo-object.

  • CGContextDrawLinearGradient draws a gradient in a CGContext pseudo-object; the first parameter is the CGContext pseudo-object, and the second parameter is the CGGradient pseudo-object.

Nowadays, as part of renamification, many commonly used CFTypeRef functions, especially in the Core Graphics framework, are recast as if the “subject” CFTypeRef objects were genuine class instances, with the functions themselves as initializers and instance methods. Those lines are recast in Swift like this (thanks to the mighty power of NS_SWIFT_NAME):

let con = UIGraphicsGetCurrentContext()!
let sp = CGColorSpaceCreateDeviceGray()
// ... colors and locs are arrays of CGFloat ...
let grad = CGGradient(colorSpace: sp,
    colorComponents: colors, locations: locs, count: 3)
con.drawLinearGradient(grad,
    start: CGPoint(x:89,y:0), end: CGPoint(x:111,y:0), options:[])

In that code:

  • CGColorSpaceCreateDeviceGray is unchanged.

  • CGGradientCreateWithColorComponents is turned into a CGGradient pseudo-object initializer, with external parameter names.

  • CGContextDrawLinearGradient is turned into an instance property of a CGContext pseudo-object, with external parameter names.

Many CFTypeRefs are toll-free bridged to corresponding Objective-C object types. CFString and NSString, CFNumber and NSNumber, CFArray and NSArray, CFDictionary and NSDictionary are all toll-free bridged (and there are many others). Such pairs are interchangeable by casting. This is much easier in Swift than in Objective-C. In Objective-C, ARC memory management doesn’t apply to CFTypeRefs; therefore you must perform a bridging cast, to tell Objective-C how to manage this object’s memory as it crosses between the memory-managed world of Objective-C objects and the unmanaged world of C and CFTypeRefs. But in Swift, CFTypeRefs are memory-managed, and so there is no need for a bridging cast; you can just cast, plain and simple.

In this code from one of my apps, I’m using the ImageIO framework. This framework has a C API (which has not been renamified) and uses CFTypeRefs. CGImageSourceCopyPropertiesAtIndex returns a CFDictionary whose keys are CFStrings. The easiest way to obtain a value from a dictionary is by subscripting, but you can’t do that with a CFDictionary, because it isn’t an object — so I cast it to a Swift dictionary. The key kCGImagePropertyPixelWidth is a CFString, but when I try to use it directly in a subscript, Swift allows me to do so:

let d = CGImageSourceCopyPropertiesAtIndex(src, 0, nil) as! [AnyHashable:Any]
let width = d[kCGImagePropertyPixelWidth] as! CGFloat

Similarly, in this code, I form a dictionary d using CFString keys — and then I pass it to the CGImageSourceCreateThumbnailAtIndex function where a CFDictionary is expected:

let d : [AnyHashable:Any] = [
    kCGImageSourceShouldAllowFloat : true,
    kCGImageSourceCreateThumbnailWithTransform : true,
    kCGImageSourceCreateThumbnailFromImageAlways : true,
    kCGImageSourceThumbnailMaxPixelSize : w
]
let imref = CGImageSourceCreateThumbnailAtIndex(src, 0, d as CFDictionary)!

A CFTypeRef is a pointer (to a pseudo-object), so it is interchangeable with C pointer-to-void. This can result in a perplexing situation in Swift. If a C API casts a CFTypeRef as a pointer-to-void, Swift will see it as an UnsafeRawPointer. How can you cast between this and the actual CFTypeRef? You cannot use the memory binding technique that I used earlier to turn an UnsafeRawPointer into an UnsafePointer generic, because the CFTypeRef does not lie at the far end of the pointer; it is the pointer.

We might simply call the global unsafeBitCast function, but that’s dangerous (as the name suggests), because it gives the resulting CFTypeRef no memory management. The correct approach is to pass through an Unmanaged generic to apply memory management; its fromOpaque static method takes an UnsafeRawPointer, and its toOpaque instance method yields an UnsafeMutableRawPointer. (I owe this technique to Martin R.; see http://stackoverflow.com/a/33310021/1187415.)

To illustrate, I’ll repeat the earlier example where I called CGImageSourceCopyPropertiesAtIndex, but this time I won’t cast to a Swift dictionary; I’ll work with the result as a CFDictionary to extract the value of its kCGImagePropertyPixelWidth key. To do so, I’ll call CFDictionaryGetValue, which takes an UnsafeRawPointer parameter and returns an UnsafeRawPointer result. To form the parameter, I’ll cast a CFString to an UnsafeMutableRawPointer; to work with the result, I’ll cast an UnsafeRawPointer to a CFNumber. No one in his right mind would ever write this code, but it does work:

let result = CGImageSourceCopyPropertiesAtIndex(src, 0, nil)!
let key = kCGImagePropertyPixelWidth // CFString
let p1 = Unmanaged.passUnretained(key).toOpaque() // UnsafeMutableRawPointer
let p2 = CFDictionaryGetValue(result, p1) // UnsafeRawPointer
let n = Unmanaged<CFNumber>.fromOpaque(p2!).takeUnretainedValue() // CFNumber
var width : CGFloat = 0
CFNumberGetValue(n, .cgFloatType, &width) // width is now 640.0

Blocks

A block is a C language feature introduced by Apple starting in iOS 4. It is very like a C function, but it behaves as a closure and can be passed around as a reference type. A block, in fact, is parallel to a Swift function, and the two are interchangeable: you can pass a Swift function where a block is expected, and when a block is handed to you by Cocoa it appears as a function.

In C and Objective-C, a block declaration is signified by the caret character (^), which appears where an asterisk would appear in a C pointer-to-function declaration. The NSArray instance method sortedArrayUsingComparator: takes an NSComparator parameter, which is defined through a typedef like this:

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);

That says: “An NSComparator is a block taking two id parameters and returning an NSComparisonResult.” In Swift, therefore, that typedef is translated as the function signature (Any, Any) -> ComparisonResult. It is then trivial to supply a function of the required type as argument when you call sortedArray(comparator:) in Swift:

let arr = ["Mannyz", "Moey", "Jackx"]
let arr2 = (arr as NSArray).sortedArray { s1, s2 in
    let c1 = String((s1 as! String).last!)
    let c2 = String((s2 as! String).last!)
    return c1.compare(c2)
} // [Jackx, Moey, Mannyz]

In many cases, there won’t be a typedef, and the type of the block will appear directly in a method declaration. Here’s the Objective-C declaration for a UIView class method that takes two block parameters:

+ (void)animateWithDuration:(NSTimeInterval)duration
    animations:(void (^)(void))animations
    completion:(void (^ __nullable)(BOOL finished))completion;

In that declaration, animations: is a block taking no parameters (void) and returning no value, and completion: is a block taking one BOOL parameter and returning no value. Here’s the Swift translation:

class func animate(withDuration duration: TimeInterval,
    animations: @escaping () -> Void,
    completion: ((Bool) -> Void)? = nil)

That’s a method that you would call, passing a function as argument where a block parameter is expected (and see Chapter 2 for an example of actually doing so). Here’s a method that you would implement, where a function is passed to you. This is the Objective-C declaration:

- (void)webView:(WKWebView *)webView
    decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
    decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

You implement this method, and it is called when the user taps a link in a web view, so that you can decide how to respond. The third parameter is a block that takes one parameter — a WKNavigationActionPolicy, which is an enum — and returns no value. The block is passed to you as a Swift function, and you respond by calling the function to report your decision:

func webView(_ webView: WKWebView,
    decidePolicyFor navigationAction: WKNavigationAction,
    decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        // ...
        decisionHandler(.allow)
}

A C function is not a block, but you can also use a Swift function where a C function is expected, as I demonstrated earlier. Going in the other direction, to declare a type as a C pointer-to-function, mark the type as @convention(c). Here are two Swift method declarations:

func blockTaker(_ f:() -> ()) {}
func functionTaker(_ f:@convention(c)() -> ()) {}

Objective-C sees the first as taking a block, and the second as taking a pointer-to-function.

API Markup

In the early days of Swift, its static strict typing was a poor match for Objective-C’s dynamic loose typing, and this made the Swift versions of Objective-C methods ugly and unpleasant:

Too many Optionals

In Objective-C, any object instance reference can be nil. But in Swift, only an Optional can be nil. The default solution was to use implicitly unwrapped Optionals as the medium of object interchange between Objective-C and Swift. But this was ugly, and a blunt instrument, especially because most objects arriving from Objective-C were never in fact going to be nil.

Too many umbrella collections

In Objective-C, a collection type such as NSArray can contain elements of multiple object types, and the collection itself is agnostic as to what types of elements it contains. But a Swift collection type can contain elements of just one type, and is itself typed according to that element type. The default solution was for every collection to arrive from Objective-C typed as having AnyObject elements; it then had to be cast down explicitly on the Swift side. This was infuriating. You would ask for a view’s subviews and get back an Array of AnyObject, which then had to be cast down to an Array of UIView — when nothing could be more obvious than that a view’s subviews would in fact all be UIView objects.

These problems were subsequently solved by modifying the Objective-C language to permit markup of declarations in such a way as to communicate to Swift a more specific knowledge of what to expect.

Nullability

An Objective-C object type can be marked as nullable or nonnull, to specify, respectively, that it might or will never be nil. In the same way, C pointer types can be marked __nullable or __nonnull. Using these markers generally obviates the need for implicitly unwrapped Optionals as a medium of interchange; every type can be either a normal type or a simple Optional, and if it’s an Optional, there’s a good reason for it. Implicitly unwrapped Optionals are a rare sight in the Cocoa APIs nowadays.

If you’re writing an Objective-C header file and you don’t mark up any of it as to nullability, you’ll return to the bad old days: Swift will see your types as implicitly unwrapped Optionals. Here’s an Objective-C method declaration:

- (NSString*) badMethod: (NSString*) s;

In the absence of markup, Swift sees that as:

func badMethod(_ s: String!) -> String!

Clearly our Objective-C needs some markup! As soon as your header file contains any markup, the Objective-C compiler will complain until it is completely marked up. As a shortcut, you can mark an entire stretch of your header file with a default nonnull setting, so that only the exceptional nullable types will need explicit markup, like this:

NS_ASSUME_NONNULL_BEGIN
- (NSString*) badMethod: (NSString*) s;
- (nullable NSString*) goodMethod: (NSString*) s;
NS_ASSUME_NONNULL_END

Swift sees that with no implicitly unwrapped Optionals:

func badMethod(_ s: String) -> String
func goodMethod(_ s: String) -> String?

You can use the Clang analyzer (Product → Analyze) to help audit the correctness of your nullability markup, but in the end it’s your responsibility to tell the truth. If you still want a type to appear as an implicitly unwrapped Optional (perhaps because you’re just not sure what the truth is), mark it null_unspecified.

Lightweight generics

To mark an Objective-C collection type as containing a certain type of element, the element type can appear in angle brackets (<>) between the name of the collection type and the asterisk. Here’s an Objective-C method that returns an array of strings:

- (NSArray<NSString*>*) pepBoys;

Swift sees the return type of that method as [String], and there will be no need to cast it down.

In the declaration of an actual Objective-C collection type, a placeholder name stands for the type in angle brackets. The declaration for NSArray starts like this:

@interface NSArray<ObjectType>
- (NSArray<ObjectType> *)arrayByAddingObject:(ObjectType)anObject;
// ...

The first line says that we’re going to use ObjectType as the placeholder name for the element type. The second line says that the arrayByAddingObject: method takes an object of the element type and returns an array of the element type. If a particular array is declared as NSArray<NSString*>*, the ObjectType placeholder would be resolved to NSString*. Apple refers to this sort of markup as a lightweight generic, and you can readily see why.

In Swift, classes marked up as lightweight generics are imported into Swift as actual generics even if they are not bridged collection types. Suppose I declare my own Objective-C class, parallel to NSArray:

@interface Thing<ObjectType> : NSObject
- (void) giveMeAThing:(nonnull ObjectType)anObject;
@end

The Thing class arrives into Swift declared as a generic:

class Thing<ObjectType> : NSObject where ObjectType : AnyObject {

Thing has to be instantiated by resolving the generic somehow. Often, it will be resolved explicitly:

let t = Thing<NSString>()
t.giveMeAThing("howdy") // an Int would be illegal here

Bilingual Targets

It is legal for a target to be a bilingual target — one that contains both Swift files and Objective-C files. A bilingual target can be useful for various reasons. You might want to take advantage of Objective-C language features. You might want to incorporate third-party code written in Objective-C. You might want to incorporate your own existing code written in Objective-C. Your app itself may have been written in Objective-C originally, and now you want to migrate part of it (or all of it, in stages) into Swift. The key question is how, within a single target, Swift and Objective-C hear about one another’s code in the first place.

Objective-C, unlike Swift, has a visibility problem already: Objective-C files cannot automatically see one another. Instead, each Objective-C file that needs to see another Objective-C file must be instructed explicitly to see that file, usually with an #import directive at the top of the first file:

  • In order to prevent unwanted exposure of private information, an Objective-C class declaration is conventionally spread over two files: a header file (.h) containing the @interface section, and a code file (.m) containing the @implementation section.

  • Also conventionally, only .h files are ever imported. If declarations of class members, constants, and so forth are to be public, they are placed in a .h file.

Visibility of Swift and Objective-C to one another depends upon those conventions: it works through .h files. There are two directions of visibility, and they operate separately through two special Objective-C header files:

How Swift sees Objective-C

When you add a Swift file to an Objective-C target, or an Objective-C file to a Swift target, Xcode offers to create a bridging header. This is a .h file in the project. Its default name is derived from the target name — such as MyCoolApp-Bridging-Header.h — but the name is arbitrary and can be changed, provided you change the target’s Objective-C Bridging Header build setting to match. (Similarly, if you decline the bridging header and you decide later that you want one, create a .h file manually and point to it in the target’s Objective-C Bridging Header build setting.) An Objective-C .h file will then be visible to Swift if you #import it in this bridging header.

How Objective-C sees Swift

When you build your target, the appropriate top-level declarations of all your Swift files are automatically translated into Objective-C and are used to construct a generated interface header within the Intermediates build folder for this target, deep inside your DerivedData folder. For a target called MyCoolApp, the generated interface header is called MyCoolApp-Swift.h. The name may involve some transformation; a space in the target name is translated into an underscore. You can examine or change the header name with the target’s Objective-C Generated Interface Header Name build setting. The generated interface header is how your Swift code is exposed to Objective-C in general (even in a single-language Swift project); your own Objective-C files will be able to see your Swift declarations if you #import the generated interface header into each Objective-C file that needs to see them.

To sum up:

  • The bridging header is visible in your project navigator; you write an #import statement here to make your Objective-C declarations visible to Swift.

  • The generated interface header is squirreled away in the DerivedData folder; you #import it to make your Swift declarations visible to your Objective-C code.

Here’s an actual example. Let’s say that I’ve added to my Swift target, called MyCoolApp, a Thing class written in Objective-C. It is distributed over two files, Thing.h and Thing.m. Then:

  • For Swift code to see the Thing class, I need to #import "Thing.h" in the bridging header (MyCoolApp-Bridging-Header.h).

  • For Thing class code to see my Swift declarations, I need to #import "MyCoolApp-Swift.h" (the generated bridging header) at the top of Thing.m.

That’s how Objective-C and Swift are able to see one another; but what do Objective-C and Swift see when they see one another? Xcode makes it easy to find out, using the code editor’s Related Items menu (Control-1). It contains a Generated Interface hierarchical menu:

  • In an Objective-C header file (such as Thing.h), the Generated Interface menu lists the Swift interface. Choose it to see how these Objective-C declarations are translated into Swift.

  • In a Swift file, the Generated Interface menu lists the Objective-C generated interface header. Choose it to see how your target’s Swift declarations are translated into Objective-C.

Before Swift existed, all my iOS apps were written in Objective-C. When Swift came along, I translated those apps into Swift. I quickly developed a step-by-step procedure for doing that; here it is:

  1. Pick a .m file to be translated into Swift. Objective-C cannot subclass a Swift class, so if you have defined both a class and its subclass in Objective-C, start with the subclass. (Leave the app delegate class for last.)

  2. Remove that .m file from the target. To do so, select the .m file and use the File inspector.

  3. In every Objective-C file that #imports the corresponding .h file, remove that #import statement and import in its place the generated interface header (if you aren’t importing it in this file already).

  4. If you were importing the corresponding .h file in the bridging header, remove the #import statement.

  5. Create the .swift file for this class. Make sure it is added to the target.

  6. In the .swift file, declare the class and provide stub declarations for all members that were being made public in the .h file. If this class needs to adopt Cocoa protocols, adopt them; you may have to provide stub declarations of required protocol methods as well. If this file needs to refer to any other classes that your target still declares in Objective-C, import their .h files in the bridging header.

  7. The project should now compile! It doesn’t work, of course, because you have not written any real code in the .swift file. But who cares about that? Time for a beer!

  8. Now fill out the code in the .swift file. My technique is to translate more or less line-by-line from the original Objective-C code at first, even though the outcome is not particularly idiomatic or Swifty.

  9. When the code for this .m file is completely translated into Swift, build and run and test. If the runtime complains (probably accompanied by crashing) that it can’t find this class, find all references to it in the nib editor and reenter the class’s name in the Identity inspector (and press Tab to set the change). Save and try again.

  10. On to the next .m file! Repeat all of the above steps.

  11. When all of the other files have been translated, translate the app delegate class. At this point, if there are no Objective-C files left in the target, you can delete the main.m file (replacing it with a @main attribute in the app delegate class declaration) and the .pch (precompiled header) file.

Your app should now run, and is rewritten in pure Swift (or is, at least, as pure as you intend to make it). Now go back and think about the code, making it more Swifty and idiomatic. You may well find that things that were clumsy or tricky in Objective-C can be made much neater and clearer in Swift.

You can also do a partial conversion of an Objective-C class by extending it in Swift. That can be useful as a stage along the path to total conversion, or you might quite reasonably write only one or two methods of an Objective-C class in Swift, just because Swift makes it so much easier to say or understand certain kinds of thing. However, Swift cannot see the Objective-C class’s members unless they are made public, so methods and properties that you were previously keeping private in the Objective-C class’s .m file may have to be declared in its .h file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.80.45