Guides and Sample Code

Developer

Using Swift with Cocoa and Objective-C (Swift 4)

iBooks
On This Page

Working with Cocoa Frameworks

As part of its interoperability with Objective-C, Swift offers convenient and efficient ways of working with Cocoa frameworks.

Swift automatically converts some Objective-C types to Swift types, and some Swift types to Objective-C types. Types that can be converted between Objective-C and Swift are referred to as bridged types. For example, in Swift code, you can pass a String value to an Objective-C method declared to take an NSString parameter. In addition, many of the Cocoa frameworks, including Foundation, AppKit, and UIKit refine their APIs to be more natural in Swift. For example, the NSCoder method decodeObjectOfClass(_:forKey:) uses Swift generics to provide a stronger type signature.

Foundation

The Foundation framework provides a base layer of functionality for apps and frameworks, including data storage, text processing, dates and times, sorting and filtering, persistence, and networking.

Bridged Types

The Swift Foundation overlay provides the following bridged value types for the following Objective-C reference types:

Objective-C Reference Type

Swift Value Type

NSAffineTransform

AffineTransform

NSArray

Array

NSCalendar

Calendar

NSCharacterSet

CharacterSet

NSData

Data

NSDateComponents

DateComponents

NSDateInterval

DateInterval

NSDate

Date

NSDecimalNumber

Decimal

NSDictionary

Dictionary

NSIndexPath

IndexPath

NSIndexSet

IndexSet

NSLocale

Locale

NSMeasurement

Measurement

NSNotification

Notification

NSNumber

Swift numeric types (Int, Float, and so on.)

NSPersonNameComponents

PersonNameComponents

NSSet

Set

NSString

String

NSTimeZone

TimeZone

NSURL

URL

NSURLComponents

URLComponents

NSURLQueryItem

URLQueryItem

NSURLRequest

URLRequest

NSUUID

UUID

These value types have the same functionality as their corresponding reference types. Class clusters that include immutable and mutable subclasses are bridged to a single value type. Swift code uses var and let to control mutability, so it doesn’t need both classes. The corresponding reference types can be accessed with their original NS class name prefix.

Anywhere you can use a bridged Objective-C reference type, you can use the Swift value type instead. This lets you take advantage of the functionality available on the reference type’s implementation in a way that is natural in Swift code. For this reason, you should almost never need to use a bridged reference type directly in your own code. In fact, when Swift code imports Objective-C APIs, the importer replaces Objective-C reference types with their corresponding value types. Likewise, when Objective-C code imports Swift APIs, the importer also replaces Swift value types with their corresponding Objective-C reference types.

One of the primary advantages of value types over reference types is that they make it easier to reason about your code. For more information about value types, see Classes and Structures in The Swift Programming Language (Swift 4), and WWDC 2015 session 414 Building Better Apps with Value Types in Swift.

If you do need to use a bridged Foundation object, you can cast between bridged types using the as type casting operator.

Renamed Types

The Swift Foundation overlay renames classes and protocols, as well as related enumerations and constants.

Imported Foundation classes and protocols drop their NS prefix, with the following exceptions:

  • Classes specific to Objective-C or inherently tied to the Objective-C runtime, such as NSObject, NSAutoreleasePool, NSException, and NSProxy

  • Platform-specific classes, such as NSBackgroundActivity, NSUserNotification, and NSXPCConnection

  • Classes that have a value type equivalent, as described in Bridged Types, such as NSString, NSDictionary, and NSURL

  • Classes that do not have a value type equivalent but are planned to have one in the near future, such as NSAttributedString, NSRegularExpression, and NSPredicate

Foundation classes often declare enumeration or constant types. When importing these types, Swift moves them to be nested types of their related types. For example, the NSJSONReadingOptions option set is imported as JSONSerialization.ReadingOptions.

Strings

Swift bridges between the String type and the NSString class. You can create an NSString object by casting a String value using the as operator. You can also create an NSString object using a string literal by explicitly providing a type annotation.

  1. import Foundation
  2. let string: String = "abc"
  3. let bridgedString: NSString = string as NSString
  4. let stringLiteral: NSString = "123"
  5. if let integerValue = Int(stringLiteral as String) {
  6. print("\(stringLiteral) is the integer \(integerValue)")
  7. }
  8. // Prints "123 is the integer 123"

Numbers

Swift bridges between the NSNumber class and Swift numeric types, including Int, Double, and Bool.

You can create an NSNumber object by casting a Swift number value using the as operator. Because NSNumber can contain a variety of different types, you must use the as? operator when casting to a Swift number type. For example, casting an NSNumber value representing the number 500 to the Int8 Swift type will fail and return nil, because the largest value that an Int8 value can represent is 127.

You can also create an NSNumber object using a floating-point, integer, or Boolean literal by explicitly providing a type annotation.

  1. import Foundation
  2. let number = 42
  3. let bridgedNumber: NSNumber = number as NSNumber
  4. let integerLiteral: NSNumber = 5
  5. let floatLiteral: NSNumber = 3.14159
  6. let booleanLiteral: NSNumber = true

Arrays

Swift bridges between the Array type and the NSArray class. When you bridge from an NSArray object with a parameterized type to a Swift array, the element type of the resulting array is bridged as well. If an NSArray object does not specify a parameterized type, it is bridged to a Swift array of type [Any].

For example, consider the following Objective-C declarations:

  1. @property NSArray *objects;
  2. @property NSArray<NSDate *> *dates;
  3. - (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
  4. - (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

Here’s how Swift imports them:

  1. var objects: [Any]
  2. var dates: [Date]
  3. func datesBeforeDate(date: Date) -> [Date]
  4. func addDatesParsedFromTimestamps(timestamps: [String])

You can also create an NSArray object directly from a Swift array literal, following the same bridging rules outlined above. When you explicitly type a constant or variable as an NSArray object and assign it an array literal, Swift creates an NSArray object instead of a Swift array.

  1. let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"]
  2. // schoolSupplies is an NSArray object containing three values

Sets

In addition to arrays, Swift bridges between the Set type and the NSSet class. When you bridge from an NSSet object with a parameterized type to a Swift set, the resulting set is of type Set<ObjectType>. If an NSSet object does not specify a parameterized type, it is bridged to a Swift set of type Set<AnyHashable>.

For example, consider the following Objective-C declarations:

  1. @property NSSet *objects;
  2. @property NSSet<NSString *> *words;
  3. - (NSSet<NSString *> *)wordsMatchingPredicate:(NSPredicate *)predicate;
  4. - (void)removeWords:(NSSet<NSString *> *)words;

Here’s how Swift imports them:

  1. var objects: Set<AnyHashable>
  2. var words: Set<String>
  3. func wordsMatchingPredicate(predicate: NSPredicate) -> Set<String>
  4. func removeWords(words: Set<String>)

You can also create an NSSet object directly from a Swift array literal, following the same bridging rules outlined above. When you explicitly type a constant or variable as an NSSet object and assign it an array literal, Swift creates an NSSet object instead of a Swift set.

  1. let amenities: NSSet = ["Sauna", "Steam Room", "Jacuzzi"]
  2. // amenities is an NSSet object containing three values

Dictionaries

Swift also bridges between the Dictionary type and the NSDictionary class. When you bridge from an NSDictionary object with parameterized types to a Swift dictionary, the resulting dictionary is of type [Key: Value]. If an NSDictionary object does not specify parameterized types, it is bridged to a Swift dictionary of type [AnyHashable: Any].

For example, consider the following Objective-C declarations:

  1. @property NSDictionary *keyedObjects;
  2. @property NSDictionary<NSURL *, NSData *> *cachedData;
  3. - (NSDictionary<NSURL *, NSNumber *> *)fileSizesForURLsWithSuffix:(NSString *)suffix;
  4. - (void)setCacheExpirations:(NSDictionary<NSURL *, NSDate *> *)expirations;

Here’s how Swift imports them:

  1. var keyedObjects: [AnyHashable: Any]
  2. var cachedData: [URL: Data]
  3. func fileSizesForURLsWithSuffix(suffix: String) -> [URL: NSNumber]
  4. func setCacheExpirations(expirations: [URL: NSDate])

You can also create an NSDictionary object directly from a Swift dictionary literal, following the same bridging rules outlined above. When you explicitly type a constant or variable as an NSDictionary object and assign it a dictionary literal, Swift creates an NSDictionary object instead of a Swift dictionary.

  1. let medalRankings: NSDictionary = ["Gold": "1st Place", "Silver": "2nd Place", "Bronze": "3rd Place"]
  2. // medalRankings is an NSDictionary object containing three key-value pairs

Core Foundation

Core Foundation types are imported as Swift classes. Wherever memory management annotations have been provided, Swift automatically manages the memory of Core Foundation objects, including Core Foundation objects that you instantiate yourself. In Swift, you can use each pair of toll-free bridged Foundation and Core Foundation types interchangeably. You can also bridge some toll-free bridged Core Foundation types to Swift standard library types if you cast to a bridging Foundation type first.

Remapped Types

When Swift imports Core Foundation types, the compiler remaps the names of these types. The compiler removes Ref from the end of each type name because all Swift classes are reference types, therefore the suffix is redundant.

The Core Foundation CFTypeRef type completely remaps to the AnyObject type. Wherever you would use CFTypeRef, you should now use AnyObject in your code.

Memory Managed Objects

Core Foundation objects returned from annotated APIs are automatically memory managed in Swift—you do not need to invoke the CFRetain, CFRelease, or CFAutorelease functions yourself.

If you return Core Foundation objects from your own C functions and Objective-C methods, you can annotate them with either the CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED macro to automatically insert memory management calls. You can also use the CF_IMPLICIT_BRIDGING_ENABLED and CF_IMPLICIT_BRIDGING_DISABLED macros to enclose C function declarations that follow Core Foundation ownership policy naming policy in order to infer memory management from naming.

If you use only annotated APIs that do not indirectly return Core Foundation objects, you can skip the rest of this section. Otherwise, continue on to learn about working with unmanaged Core Foundation objects.

Unmanaged Objects

When Swift imports APIs that have not been annotated, the compiler cannot automatically memory manage the returned Core Foundation objects. Swift wraps these returned Core Foundation objects in an Unmanaged<Instance> structure. All indirectly returned Core Foundation objects are unmanaged as well. For example, here’s an unannotated C function:

  1. CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2)

And here’s how Swift imports it:

  1. func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged<CFString>! {
  2. // ...
  3. }

When you receive an unmanaged object from an unannotated API, you should immediately convert it to a memory managed object before you work with it. That way, Swift can handle memory management for you. The Unmanaged<Instance> structure provides two methods to convert an unmanaged object to a memory managed object—takeUnretainedValue() and takeRetainedValue(). Both of these methods return the original, unwrapped type of the object. You choose which method to use based on whether the API you are invoking returns an unretained or retained object.

For example, suppose the C function above does not retain the CFString object before returning it. To start using the object, you use the takeUnretainedValue() function.

  1. let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
  2. // memoryManagedResult is a memory managed CFString

You can also invoke the retain(), release(), and autorelease() methods on unmanaged objects, but this approach is not recommended.

For more information, see Ownership Policy in Memory Management Programming Guide for Core Foundation.

Unified Logging

The unified logging system provides an API for capturing messaging across all levels of the system, and is a replacement for the NSLog function in the Foundation framework. Unified logging is available in iOS 10.0 and later, macOS 10.12 and later, tvOS 10.0 and later, and watchOS 3.0 and later.

In Swift, you can interact with the unified logging system using the top level os_log(_:dso:log:type:_:) function, found in the log submodule of the os module.

  1. import os.log
  2. os_log("This is a log message.")

You can format a log message using an NSString or printf format string along with one or more trailing arguments.

  1. let fileSize = 1234567890
  2. os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize)

You can also specify a log level defined by the logging system, such as Info, Debug, or Error, in order to control how log messages are handled according to the importance of the logging event. For example, information that may be helpful, but isn’t essential for troubleshooting errors should be logged at the Info level.

  1. os_log("This is additional info that may be helpful for troubleshooting.", type: .info)

To log a message to a specific subsystem, you can create a new OSLog object, specifying the subsystem and category, and pass it as a parameter to the os_log function.

  1. let customLog = OSLog("com.your_company.your_subsystem_name.plist", "your_category_name")
  2. os_log("This is info that may be helpful during development or debugging.", log: customLog, type: .debug)

For more information about the unified logging system, see Logging.

Cocoa Structures

When bridging from Swift code back into Objective-C code, built-in structures from Cocoa and Foundation are bridged as NSValue instances. As a result, you can use an Objective-C structure from Swift in Cocoa APIs that accept only instances of reference types. This is true even though the instance’s defining type is bridged to Swift as a structure type.

The following structures are bridged to NSValue:

  • CATransform3D

  • CLLocationCoordinate2D

  • CGAffineTransform

  • CGPoint

  • CGRect

  • CGSize

  • CGVector

  • CMTimeMapping

  • CMTimeRange

  • CMTime

  • MKCoordinateSpan

  • NSRange

  • SCNMatrix4

  • SCNVector3

  • SCNVector4

  • UIEdgeInsets

  • UIOffset