Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vprtwn/9e30c063e2b00649352d to your computer and use it in GitHub Desktop.
Save vprtwn/9e30c063e2b00649352d to your computer and use it in GitHub Desktop.

Working with Cocoa

Implicitly Unwrapped Optionals

  • A value of class type in Swift is never nil
    • var fileModificationDate: NSDate!
  • Objective-C does not have a notion of a "never-nil" pointer
  • ! is an implicitly unwrapped optional
    • can be tested explicitly for nil
    • can directly access properties/methods of the underlying value
    • can be implicitly converted to its underlying value

Mapping Objective-C Types to Swift

* `BOOL` -> `Bool`
* `SEL` -> `Selector`
* `id` -> `AnyObject!`
* `Class` -> `AnyClass!`
* `NSArray *` -> `AnyObject[]!`

Methods

  • Argument labels and internal parameter names
    • internal parameter name is defaults to argument label, but can be specified
  • Blocks and closures
    • blocks become implicitly unwrapped optional closures

Factory Methods are now Initializers

init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
let color = UIColor(red: 1, green: 1, blue: 1, alpha: 0)

Errors

func contentsForType(typeName: String!, error: NSErrorPointer) -> AnyObject!

var error: NSError?
if let contents = document.contentsForType("public.presentation", error: &error) {

} else if let actualError = error {

}

Modernizing your Objective-C

  • Properties
  • instancetype
  • NS_ENUM/NS_OPTIONS
  • NS_DESIGNATED_INITIALIZER
  • New Objective-C modernizer
    • see What's New in LLVM talk

id in Objective-C

  • Upcasts
  • Message sends
  • Subscripting
  • messaging id or AnyObject can result in unrecognized selector
    • Methods are optional in Swift -> no more respondsToSelector
    • object.removeFromSuperview?()
  • AnyObject does not implicitly downcast
    • let view: UIView = object // error
    • as operator forces the downcast
      • let view = object as UIView
    • as? operator performs a conditional downcast
      • if let view = object as? UIView { }

Protocols

  • @optional and @required
    • required by default
  • @property id <UITableViewDataSource> dataSource
  • var dataSource: UITableViewDataSource!
  • Testing protocol conformance
    • use conditional downcast as? operator
    • if let dataSource = object as? UITableViewDataSource {
  • Optional methods in protocols
    • if let numSections = dataSource.numberOfSectionsInTableView?(tableView) {

Bridging Core Cocoa Types

Native Strings, Arrays, Dictionaries

  • One set of general-purpose native value types
    • safe by default
    • predictable performance
    • typed collections support items of any type
  • Bridged to Cocoa NSString, NSArray, NSDictionary

Native String type

  • String is efficient, Unicode-compliant
  • Value semantics
  • Low-level operations (length, characterAtIndex are not provided by String)
    • countElements can be used to count the number of characters
    • UTF-16 is available as a property
      • for codePoint in dog.utf16 {
  • Foundation NSString APIs are available on String
  • To use your own categories, cast to NSString
    • Or extend String

NSArray bridges to Array of AnyObject

  • Upcasting Arrays
    • An Array T[] can be assigned to an AnyObject[]
  • Iteration over an AnyObject[] produces AnyObject` values
  • Can downcast AnyObject[] to an array of a specific type
    • for item in toolbarItems as UIBarButtonItem[]
  • Array bridging - under the hood
    • Swift array has two representations
      • Native
        • length, capacity, buffer of elements
      • Cocoa
        • NSArray object
    • Array methods manage the representation internally
    • Bridging converts between NSArray and a Swift array
    • Native array representation has "isa" pointer to NSArray object

Subclassing Objective-C Classes

  • Swift classes are "id compatible"
    • Same layout as an Objective-C class
    • Same basic infrastructure (retain/release/class/etc)

Overriding and NSError**

  • NSErrorPointer is Swift's version of NSError**
    • NSErrorPointer can be tested for nil, has memory property
    • error.memory = NSError(domain:

Your swift class in Objective-C

SWIFT_CLASS("MyApp.MyDocument") // mangled in internals

Limitations of Objective-C

  • Methods with tuples, generics, etc. are not expressible in objective-C
  • @objc func myGenericMethod<T>(x: T) -> (String, String) { ... }
    • compiler verifies that the declaration can be used in objective C
  • objc attribute can be used to change the name of an Objective-C method or the name of a class
var enabled: Bool { 
	@objc(isEnabled) get { ... }
	set { ... }
}

// You want to use MyDocument but keep compatibility with old archives
@objc(ABCMyDocument) class MyDocument : UIDocument {
	// ...
}

CF Interoperability

CF in Objective-C

  • Lots of bridge casts
  • C arrays, NSArray, CFArrayRef
  • CGPointMake
  • CGColorSpaceRelease

CF in Swift

  • Managed CF Objects
    • let colorSpace = CGColorSpaceCreateDeviceRGB() // inferred as CGColorSpace
      • colorSpace is automatically released
    • let gradient = CGGradientCreateWithColors(colorSpace, [startColor, endCOlor], [0.0, 1.0])
    • let startPoint = CGPoint(x: width / 2, y: 0)
      • just made a C struct!

Explicitly Bridged APIs

  • Some CF APIs have not been audited for implicit bridging
  • Swift uses Unmanaged<T> when the ownership convention is unknown
  • Unmanaged<T> enables manual memory management
    • generic struct
    • let color = CGColorGetRandomColor().takeUnretainedValue() // inferred as CGColor
  • Audit CF APIs to ensure they conform to CF memory conventions
CF_IMPLICIT_BRIDGING_ENABLED
// your CF APIs
CF_IMPLICIT_BRIDGING_DISABLED
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment