iOS Developer Library — Prerelease

Developer

Using Swift with Cocoa and Objective-C

iBooks
On This Page

Interacting with C APIs

As part of its interoperability with Objective-C, Swift maintains compatibility with a number of C language types and features. Swift also provides a way of working with common C constructs and patterns, in case your code requires it.

Primitive Types

Swift provides equivalents of C primitive integer types—for example, char, int, float, and double. However, there is no implicit conversion between these types and core Swift integer types, such as Int. Therefore, use these types if your code specifically requires them, but use Int wherever possible otherwise.

C Type

Swift Type

bool

CBool

char, signed char

CChar

unsigned char

CUnsignedChar

short

CShort

unsigned short

CUnsignedShort

int

CInt

unsigned int

CUnsignedInt

long

CLong

unsigned long

CUnsignedLong

long long

CLongLong

unsigned long long

CUnsignedLongLong

wchar_t

CWideChar

char16_t

CChar16

char32_t

CChar32

float

CFloat

double

CDouble

Enumerations

Swift imports any C-style enumeration marked with the NS_ENUM macro as a Swift enumeration. The prefixes to Objective-C enumeration value names are truncated when they are imported into Swift, whether they’re defined in system frameworks or in custom code.

For example, see this Objective-C enumeration declaration:

  1. typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
  2. UITableViewCellStyleDefault,
  3. UITableViewCellStyleValue1,
  4. UITableViewCellStyleValue2,
  5. UITableViewCellStyleSubtitle
  6. };

In Swift, it’s imported like this:

  1. enum UITableViewCellStyle: Int {
  2. case Default
  3. case Value1
  4. case Value2
  5. case Subtitle
  6. }

When you refer to an enumeration value, use the value name with a leading dot (.).

  1. let cellStyle: UITableViewCellStyle = .Default

Option Sets

Swift also imports C-style enumerations marked with the NS_OPTIONS macro as a Swift option set. Option sets behave similarly to imported enumerations by truncating their prefixes to option value names.

For example, see this Objective-C options declaration:

  1. typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
  2. NSJSONReadingMutableContainers = (1UL << 0),
  3. NSJSONReadingMutableLeaves = (1UL << 1),
  4. NSJSONReadingAllowFragments = (1UL << 2)
  5. };

In Swift, it’s imported like this:

  1. struct NSJSONReadingOptions : OptionSetType {
  2. init(rawValue: UInt)
  3. static var MutableContainers: NSJSONReadingOptions { get }
  4. static var MutableLeaves: NSJSONReadingOptions { get }
  5. static var AllowFragments: NSJSONReadingOptions { get }
  6. }

In Objective-C, an option set is a bit mask of integer values. You use the bitwise OR operator (|) to combine option values, and the bitwise AND operator (&) to check for option values. You create a new option set from a constant value or expression, An empty option set is represented by the constant zero (0).

In Swift, option sets are represented by structures conforming to the OptionSetType protocol, with static variables for each option value. Option sets behave like Swift’s Set collection type. You use the insert(_:) or unionInPlace(_:) methods to add option values, the remove(_:) or subtractInPlace(_:) methods to remove option values, and the contains(_:) method to check for an option value. You create a new option set value using an array literal, accessing option values with a leading dot (.) similar to an enumeration. An empty option set can be created from an empty array literal ([]) or by calling its default initializer.

  1. let options: NSDataBase64EncodingOptions = [
  2. .Encoding76CharacterLineLength,
  3. .EncodingEndLineWithLineFeed
  4. ]
  5. let string = data.base64EncodedStringWithOptions(options)

Unions

Swift has only partial support of C union types. When importing C aggregates containing unions or bitfields, such as Foundation’s NSDecimal type, Swift cannot access unsupported fields. However, C and Objective-C APIs that have arguments of those types and/or return values of those types can be used in Swift.

Pointers

Whenever possible, Swift avoids giving you direct access to pointers. There are, however, various pointer types available for your use when you need direct access to memory. The following tables use Type as a placeholder type name to indicate syntax for the mappings.

For return types, variables, and arguments, the following mappings apply:

C Syntax

Swift Syntax

const Type *

UnsafePointer<Type>

Type *

UnsafeMutablePointer<Type>

For class types, the following mappings apply:

C Syntax

Swift Syntax

Type * const *

UnsafePointer<Type>

Type * __strong *

UnsafeMutablePointer<Type>

Type **

AutoreleasingUnsafeMutablePointer<Type>

Constant Pointers

When a function is declared as taking a UnsafePointer<Type> argument, it can accept any of the following:

  • nil, which is passed as a null pointer.

  • An UnsafePointer<Type>, UnsafeMutablePointer<Type>, or AutoreleasingUnsafeMutablePointer<Type> value, which is converted to UnsafePointer<Type> if necessary.

  • A String value, if Type is Int8 or UInt8. The string will automatically be converted to UTF8 in a buffer that lasts for the duration of the call.

  • An inout expression whose left-hand side operand is of type Type, which is passed as the address of the left-hand side identifier.

  • A [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call.

If you have declared a function like this one:

  1. func takesAPointer(x: UnsafePointer<Float>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0
  2. var p: UnsafePointer<Float> = nil
  3. takesAPointer(nil)
  4. takesAPointer(p)
  5. takesAPointer(&x)
  6. takesAPointer([1.0, 2.0, 3.0])

When a function is declared as taking a UnsafePointer<Void> argument, it can accept the same operands as UnsafePointer<Type> for any type Type.

If you have declared a function like this one:

  1. func takesAVoidPointer(x: UnsafePointer<Void>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0, y: Int = 0
  2. var p: UnsafePointer<Float> = nil, q: UnsafePointer<Int> = nil
  3. takesAVoidPointer(nil)
  4. takesAVoidPointer(p)
  5. takesAVoidPointer(q)
  6. takesAVoidPointer(&x)
  7. takesAVoidPointer(&y)
  8. takesAVoidPointer([1.0, 2.0, 3.0] as [Float])
  9. let intArray = [1, 2, 3]
  10. takesAVoidPointer(intArray)

Mutable Pointers

When a function is declared as taking an UnsafeMutablePointer<Type> argument, it can accept any of the following:

  • nil, which is passed as a null pointer

  • An UnsafeMutablePointer<Type> value

  • An inout expression whose operand is a stored lvalue of type Type, which is passed as the address of the lvalue

  • An inout [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call

If you have declared a function like this one:

  1. func takesAMutablePointer(x: UnsafeMutablePointer<Float>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0
  2. var p: UnsafeMutablePointer<Float> = nil
  3. var a: [Float] = [1.0, 2.0, 3.0]
  4. takesAMutablePointer(nil)
  5. takesAMutablePointer(p)
  6. takesAMutablePointer(&x)
  7. takesAMutablePointer(&a)

When a function is declared as taking an UnsafeMutablePointer<Void> argument, it can accept the same operands as UnsafeMutablePointer<Type> for any type Type.

If you have declared a function like this one:

  1. func takesAMutableVoidPointer(x: UnsafeMutablePointer<Void>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0, y: Int = 0
  2. var p: UnsafeMutablePointer<Float> = nil, q: UnsafeMutablePointer<Int> = nil
  3. var a: [Float] = [1.0, 2.0, 3.0], b: [Int] = [1, 2, 3]
  4. takesAMutableVoidPointer(nil)
  5. takesAMutableVoidPointer(p)
  6. takesAMutableVoidPointer(q)
  7. takesAMutableVoidPointer(&x)
  8. takesAMutableVoidPointer(&y)
  9. takesAMutableVoidPointer(&a)
  10. takesAMutableVoidPointer(&b)

Autoreleasing Pointers

When a function is declared as taking an AutoreleasingUnsafeMutablePointer<Type>, it can accept any of the following:

  • nil, which is passed as a null pointer

  • An AutoreleasingUnsafeMutablePointer<Type> value

  • An inout expression, whose operand is primitive-copied to a temporary nonowning buffer. The address of that buffer is passed to the callee, and on return, the value in the buffer is loaded, retained, and reassigned into the operand.

Note that this list does not include arrays.

If you have declared a function like this one:

  1. func takesAnAutoreleasingPointer(x: AutoreleasingUnsafeMutablePointer<NSDate?>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: NSDate? = nil
  2. var p: AutoreleasingUnsafeMutablePointer<NSDate?> = nil
  3. takesAnAutoreleasingPointer(nil)
  4. takesAnAutoreleasingPointer(p)
  5. takesAnAutoreleasingPointer(&x)

Types that are pointed to are not bridged. For example, NSString ** comes over to Swift as AutoreleasingUnsafeMutablePointer<NSString?>, not AutoreleasingUnsafeMutablePointer<String?>.

Function Pointers

C function pointers are imported into Swift as closures with C function pointer calling convention, denoted by the @convention(c) attribute. For example, a function pointer that has the type int (*)(void) in C is imported into Swift as @convention(c) () -> Int32.

When calling a function that takes a function pointer argument, you can pass a top-level Swift function or closure literal, or nil. Only Swift function types with C function pointer calling convention may be used for function pointer arguments. For example, consider Core Foundation’s CFArrayCreateMutable(_:_:_:) function. The CFArrayCreateMutable(_:_:_:) function takes a CFArrayCallBacks structure, which is initialized with function pointer callbacks:

  1. func customCopyDescription(p: UnsafePointer<Void>) -> Unmanaged<CFString>! {
  2. // return an Unmanaged<CFString>! value
  3. }
  4. var callbacks = CFArrayCallBacks(
  5. version: 0,
  6. retain: nil,
  7. release: nil,
  8. copyDescription: customCopyDescription,
  9. equal: { (p1, p2) -> DarwinBoolean in
  10. // return Bool value
  11. }
  12. )
  13. var mutableArray = CFArrayCreateMutable(nil, 0, &callbacks)

In the example above, the CFArrayCallBacks initializer uses nil values as arguments for the retain and release parameters, the customCopyDescription function as the argument for the customCopyDescription parameter, and a closure literal as the argument for the equal parameter.

Global Constants

Global constants defined in C and Objective-C source files are automatically imported by the Swift compiler as Swift global constants.

Preprocessor Directives

The Swift compiler does not include a preprocessor. Instead, it takes advantage of compile-time attributes, build configurations, and language features to accomplish the same functionality. For this reason, preprocessor directives are not imported in Swift.

Simple Macros

Where you typically used the #define directive to define a primitive constant in C and Objective-C, in Swift you use a global constant instead. For example, the constant definition #define FADE_ANIMATION_DURATION 0.35 can be better expressed in Swift with let FADE_ANIMATION_DURATION = 0.35. Because simple constant-like macros map directly to Swift global variables, the compiler automatically imports simple macros defined in C and Objective-C source files.

Complex Macros

Complex macros are used in C and Objective-C but have no counterpart in Swift. Complex macros are macros that do not define constants, including parenthesized, function-like macros. You use complex macros in C and Objective-C to avoid type-checking constraints or to avoid retyping large amounts of boilerplate code. However, macros can make debugging and refactoring difficult. In Swift, you can use functions and generics to achieve the same results without any compromises. Therefore, the complex macros that are in C and Objective-C source files are not made available to your Swift code.

Build Configurations

Swift code and Objective-C code are conditionally compiled in different ways. Swift code can be conditionally compiled based on the evaluation of build configurations. Build configurations include the literal true and false values, command line flags, and the platform-testing functions listed in the table below. You can specify command line flags using -D <#flag#>.

Function

Valid arguments

os()

OSX, iOS, watchOS

arch()

x86_64, arm, arm64, i386

A simple conditional compilation statement takes the following form:

  • #if build configuration
  • statements
  •     #else
  • statements
  • #endif

The statements consist of zero or more valid Swift statements, which can include expressions, statements, and control flow statements. You can add additional build configuration requirements to a conditional compilation statement with the && and || operators, negate build configurations with the ! operator, and add condition blocks with #elseif:

  • #if build configuration && !build configuration
  • statements
  •     #elseif build configuration
  • statements
  •     #else
  • statements
  • #endif

In contrast with condition compilation statements in the C preprocessor, conditional compilation statements in Swift must completely surround blocks of code that are self-contained and syntactically valid. This is because all Swift code is syntax checked, even when it is not compiled.