Using Cocoa data types
We have looked at several native Swift data types, such as the string, array, and dictionary types. While using these types is definitely preferred, as part of the Objective-C interoperability, Apple has provide convenient and effective ways to work with Cocoa data types from within our Swift applications.
Some of the Cocoa and Swift data types can be used interchangeably, others are automatically converted between Cocoa and Swift data types. Those data types that can be used interchangeably or converted are called bridged data types.
Swift also provides an overlay for working with foundation data types. This lets us work with foundation data types in a way that feels more like native Swift types. If we need to use these foundation data types, we need to add the following import statement to the top of the Swift file:
import Foundation
Let's take a look at how to work with some common Cocoa data types.
NSNumber
Swift will automatically bridge certain native numeric types, such as Int, UInt, Float, Bool, and Double to an NSNumber
object. This allows us to pass these native numeric types to arguments that expect an NSNumber
object. This automatic bridging only works one way because an NSNumber
object can contain various numeric types; therefore, the Swift compiler will not know which numeric type to convert the NSNumber
to. The following examples show how to go from a native Swift Int and Double to an NSNumber
, and how to convert it back to the Swift Int and Double. Let's have a look at the following code:
var inum = 7 //Creates an Int var dnum = 10.6 //Creates a Double var insnum: NSNumber = inum //Bridges the Int to a NSNumber var dnsnum: NSNumber = dnum //Bridges the Double to a NSNumber var newint = Int(insnum) //Creates an Int from a NSNumber var newdouble = Double(dnsnum) //Creates a Double from a NSNumber
In the preceding code, Swift automatically converts the inum
and dnum
to NSNumber
objects without any typecasting; however, when we try to convert the NSNumber
objects back to Int or Double types of Swift, we need to typecast the NSNumber
objects to tell Swift what type of numbers we are converting to.
NSString data type
Swift will automatically bridge between the NSString
class and the Swift native string type. This allows us to pass the native string type to arguments that expect an NSString
object. When we use mix and match to integrate Objective-C APIs with our Swift project, it automatically converts all NSString
objects to native Swift string types. When we use mix and match to import Swift APIs with our Objective-C projects, it automatically converts Swift string types to NSString
objects.
This automatic bridging allows us to call NSString
methods on our Swift strings. Swift automatically converts the string to an NSString
object, calls the method, and then converts the returned value back to a Swift string type. The following example shows how to create a path with a Swift string using the stringByAppendingPathComponent()
method of NSString
:
var str = "http://www.packtpub.com" var path = str.stringByAppendingPathComponent("swift") //path contains http://www.packtpub.com/swift
To convert an NSString
object to a string type, we will use the as
keyword. Since an NSString
object can always be converted to a string type, we do not need to use the optional version of this typecasting operator (as?
). The following example converts an NSString
object to a native Swift string type, and then calls the toInt()
method, from the Swift string type, to convert the string to an integer, as shown in the following code:
var nsstr: NSString = "1234" var num = (nsstr as String).toInt() //num contains the number 1234
In the preceding code, the num
variable will contain the number 1234
and not the string 1234
.
NSArray
Swift will automatically bridge between the NSArray
class and the Swift native array type. Since the elements of an NSArray
object are not required to be of the same type, when we bridge from an NSArray
object to a Swift array, the elements of the Swift array are set to the [AnyObject]
type. The [AnyObject]
type is an object that is an instance of an Objective-C or Swift class or can be bridged to one.
The following example shows how we can create an NSArray
object in Swift that contains both string and int types, and then creates a Swift array from that NSArray
object:
var nsarr: NSArray = ["HI","There", 1,2] var arr = nsarr as [AnyObject]
In the preceding code, nsarr: NSArray
contains four elements: HI
, There
, 1
, and 2
. In nsarr NSArray
, two of the elements are string types and two are int types. When we convert the nsarr: NSArray
to a Swift array, the arr
array becomes an array of AnyObject
types.
If the NSArray contains a specific object type, once it is bridged to a Swift array, we can downcast the Swift array of [AnyObject]
to a Swift array of the specific object types. The only catch to this downcasting is if any element of the array is not of the object type specified, the downcasting will fail and the new array will be set to nil. The following example shows how to downcast an array:
var nsarr: NSArray = ["HI","There"] var arr = nsarr as [AnyObject] var newarr = arr as? [String]
In the preceding example, newarr
will be an array of strings that contains two elements. Now, let's change the original NSArray
to include two integers, as well as the two strings. The new code will now look like this:
var nsarr: NSArray = ["HI","There", 1, 2] var arr = nsarr as [AnyObject] var newarr = arr as? [String]
Since the original NSArray
defines an array of both strings and integers, when we attempt to downcast the Swift array from an array of [AnyObject]
to an array of string, the downcasting fails and the newarr
variable is set to nil.
NSDictionary
Just like NSArray
, Swift will automatically bridge between NSDictionary
objects and the Swift dictionary types. When we bridge from an NSDictionary
object to a Swift dictionary, the resulting dictionary will be of type [NSObject: AnyObject]
. Also, like the array, we can downcast the dictionary of [NSOdbject:AnyObject]
to a dictionary of specified types. The following example shows how to create NSDictionary
, bridge the NSDictionary
object to a Swift dictionary, and, finally, downcast the Swift dictionary to the [String:String]
type:
var nsdic: NSDictionary = ["one":"HI", "two":"There"] var dic:Dictionary = nsdic var newdic = dic as? [String:String]
If we attempt to downcast the dictionary to a type that is not valid for either the key or value, the downcasting will fail and the resulting dictionary will be set to nil. The following example illustrates this where the resulting newdic
dictionary will be nil because the value associated with the two
key is an integer rather than a string.
var nsdic: NSDictionary = ["one":"HI", "two":2] var dic:Dictionary = nsdic var newdic = dic as? [String:String]