Swift - One Step Forward from ObjC 
Nissan Tsafrir // @ntsafrir // { Pix & Byte } 
www.pixandbyte.com
Swift 
Fast . Modern . Safe . Interactive
AGENDA 
Rewrite few familiar Cocoa Touch code examples 
from Obj-C to Swift by learning to use Closures, 
Enums, Switch-Case with Pattern matching and 
more.
Replace complex macros with 
functions or generics
Replace complex macros with functions 
ObjC 
! 
NSLocalizedString(@"OK",@"a comment")
Replace complex macros with functions 
Swift 
! 
NSLocalizedString("OK", comment:"comment")
Replace complex macros with functions 
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment)  
[bundle localizedStringForKey:(key) value:(val) table:(tbl)] 
! 
// shorthand macros 
#define NSLocalizedString(key, comment) … 
#define NSLocalizedStringFromTable(key, tbl, comment) … 
!! 
ObjC 
! 
NSLocalizedString(@"OK",@"a comment")
Replace complex macros with functions 
Swift 
! 
// In Foundation Module: 
! 
func NSLocalizedString(key: String, tableName: String? = default, bundle: 
NSBundle = default, value: String = default, #comment: String) -> String 
let str = NSLocalizedString("OK", comment:"comment")
Functions 
- Default parameter values 
- External parameter name used when calling the function 
- Local parameter name available only in the function scope 
- Shorthand external parameter names - #comment 
let strError = NSLocalizedString("OK") // Error 
Type '(String, tableName: String?, bundle: NSBundle, value: String, comment: String)' 
does not conform to protocol 'StringLiteralConvertible' 
let str334 = NSLocalizedString("OK", "") // Error 
func NSLocalizedString(key: String, tableName: String? = default, bundle: 
NSBundle = default, value: String = default, #comment: String) -> String 
# Same external and local param name. 
Useful for global functions
! 
Methods - Functions associated with type 
“Swift gives the first parameter name in a method a local parameter name by 
default, and gives the second and subsequent parameter names both local and 
external parameter names by default.” 
class FooClass { 
func updateText(text: String, color: UIColor) -> String { 
return "(text) color:(color)" 
} 
} 
! 
let fc = FooClass() 
fc.updateText("tlv", UIColor.blueColor()) 
! 
! 
fc.updateText("tlv", color: UIColor.blueColor()) //OK
What you can do with your exiting complex macros 
• Replace the macros with C functions 
• Create ObjC wrapper class to implement/use the macros as 
functions. 
• Use Swift functions with defaults
Closure 
"Function closures capture local state variables! 
(Objects are state data with attached behavior;! 
Closures are behaviors with attached state data! 
and without the overhead of classes.)"! 
! 
Peter Norvig
ObjC - Blocks 
__block NSNumber *someVal = @10; // strong and mutable 
__weak typeof(self) weakSelf = self; 
! 
[locationManager getCurrentLocationWithCompletion:^(CLLocation *location) { 
if (!location) { 
return; 
} 
! 
if (weakSelf.completionBlock) { // Safer to use strongSelf in here 
weakSelf.completionBlock(location); 
} 
someVal = @20; 
}]; 
!
ObjC - Blocks 
! 
typedef void(^ PBUpdateLocationCompletion)(CLLocation * location); 
! 
@property (copy, nonatomic) PBUpdateLocationCompletion completionBlock;
var successHandler : ((feed: Array) -> ())? 
var someValue = 1 
! 
successHandler = { feed in 
self.refreshFeed(feed) 
someValue = 2 
} 
Swift - Closure
request.successHandler = { [unowned self] feed in 
self.refreshFeed(feed) 
} 
Capture List
Closure Factory Method 
Image Filter Example 
func blurFilter(radius: Int) -> (image: UIImage) -> (UIImage) { 
return { image in 
return BlurImage(image, radius) 
} 
} 
! 
let blur20 = blurFilter(20) 
! 
let blurredImage = blur20(image)
Replace Delegate with Closures
class AddViewController : UIViewController { 
var didCancel : ((AddViewController) -> ())? 
var didFinish : ((AddViewController, name: String) -> ())? 
} 
class AddViewController : UIViewController { 
typealias CancelHandler = (AddViewController) -> () 
typealias FinishHandler = (AddViewController, name: String) -> () 
var didCancel : CancelHandler? 
var didFinish : FinishHandler? 
} 
Replace Delegate with Closures
if let addVC = navigationVC.topViewController as? AddViewController { 
! 
addVC.didCancel = { controller in 
self.dismissViewControllerAnimated(true, completion: nil) 
} 
addVC.didFinish = { controller, name in 
self.dismissViewControllerAnimated(true, completion: nil) 
self.addObjectWithName(name) 
} 
} 
Delegate with Closures
Replace if -isEqual-else with 
switch-case and pattern matching
Replace if-isEqual-else with switch-case and pattern matching 
if ([segue.identifier isEqualToString:@"showDetails"]) { 
//… 
} else if ([segue.identifier isEqualToString:"add"]) { 
//… 
} 
ObjC
Replace if-isEqual-else with switch-case and pattern matching 
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { 
if segue.identifier == "showDetail" { 
//... 
} else if segue.identifier == "add" { 
//.. 
} 
} 
Swift
Replace if-isEqual-else with switch-case and pattern matching 
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { 
switch segue.identifier { 
case "showDetail": 
//… 
case "add": 
//… 
default: break 
} 
} 
Swift 
Switches support any kind of data and a wide variety of comparison 
operations.
if let nvc = segue.destinationViewController as? UINavigationController { 
… 
} 
Replace if-isEqual-else with switch-case and pattern matching 
Optional binding that use optional down casting 
“Try to access viewController as a navigation controller. If this is 
successful, set a new temporary constant called nvc to the value 
stored in the returned optional UINavigationController.”
Replace if-isEqual-else with switch-case and pattern matching 
Another switch case pattern matching example 
override func prepareForSegue(segue: UIStoryboardSegue, sender: … 
{ 
switch segue.destinationViewController { 
case let nvc as UINavigationController: 
… 
case let dvc as DetailsViewController: 
… 
default: break 
} 
}
Error Reporting
Results Enumeration and associated value 
With NSErrorPointer (NSError?) 
var error : NSError? 
let url = NSURL(string: "http://www.apple.com") 
let data = NSData(contentsOfURL: url, 
options: NSDataReadingOptions.allZeros, 
error: &error) 
! 
if let anError = error { 
println("failure: (anErrror.localizedDescription())"  ) 
}
Results Enumeration and associated value 
Using Enums with associated value 
enum ServerResult { 
case Result (NSData) 
case Error (NSError) 
} 
! 
let success = ServerResult.Result(data) 
! 
let failure = ServerResult.Error(NSError(domain: "MyErrorDomain", code: 1, 
userInfo: nil)) 
switch success { 
case let .Result(data): 
let serverResponse = "Received data (data)" 
case let .Error(error): 
let serverResponse = "Failure... (error)" 
}
Setting Defaults with ?? operator
Setting Defaults with ?? operator 
ObjC 
!! 
NSString *name = text ? text : "default-name"; 
Swift 
var text : String? 
… 
! 
! 
let name = text ?? "default-name";
CoreFoundation and other C API 
Get free ARC!
Swift compiler gives CoreFoundation, 
CoreGraphics and others ARC 
/* Shape */ 
let pathRef = CGPathCreateMutable() 
CGPathMoveToPoint(pathRef, nil, 0, 0) 
CGPathAddLineToPoint(pathRef, nil, 400, 0) 
CGPathAddLineToPoint(pathRef, nil, 400, 320) 
CGPathAddLineToPoint(pathRef, nil, 0, 320) 
CGPathAddLineToPoint(pathRef, nil, 0, 0) 
CGPathCloseSubpath(pathRef) 
!! 
// Compiler take care memory management in most cases 
So no need for these: 
CGPathRelease (pathRef) or CFRelease(pathRef)
// In C 
! 
CoreGraphic Structs 
CGRectMake(0, 0, 320, 480) 
! 
// In swift - much more readable 
! 
CGRect(x: 0, y: 0, width: 400, height: 320)
GCD a bit more cleaner
GCD a bit more cleaner 
let group = dispatch_group_create() 
dispatch_group_enter(group) 
dispatch_group_leave(group) 
dispatch_group_notify(group,dispatch_get_main_queue()) { 
… 
} 
! 
dispatch_async(dispatch_get_main_queue()) { 
// trailing closure body 
} 
Type inferred, trailing closure
Singleton : Replace dispatch_once with inner 
struct
Singleton 
You can use dispatch_once but we hope for better way 
class Singleton : NSObject { 
class var sharedInstance : Singleton { 
struct Static { 
static var onceToken : dispatch_once_t = 0 
static var instance : Singleton? = nil 
} 
dispatch_once(&Static.onceToken) { 
Static.instance = Singleton() 
} 
return Static.instance! 
} 
override init() { 
println("yay"); 
} 
} 
! 
Singleton.sharedInstance
Singleton: Replace dispatch_once with inner 
struct 
Class variable currently not supported (xcode 6 beta 7) 
But structs do support static constants 
class Singleton : NSObject { 
class var sharedInstance : Singleton { 
struct Static { 
static let instance : Singleton = Singleton() 
} 
return Static.instance 
} 
override init() { 
println("yay"); 
} 
} 
Follow https://github.com/hpique/SwiftSingleton for updates
References 
! 
- Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/il/jEUH0.l 
- Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/il/1u3-0.l 
- WWDC 14 Swift videos (https://developer.apple.com/videos/wwdc/2014/) 
- Apple’s Dev Forums 
- https://github.com/hpique/SwiftSingleton
Thank You 
Nissan Tsafrir 
@ntsafrir 
nissan@pixandbyte.com

Swift - One step forward from Obj-C

  • 1.
    Swift - OneStep Forward from ObjC Nissan Tsafrir // @ntsafrir // { Pix & Byte } www.pixandbyte.com
  • 2.
    Swift Fast .Modern . Safe . Interactive
  • 3.
    AGENDA Rewrite fewfamiliar Cocoa Touch code examples from Obj-C to Swift by learning to use Closures, Enums, Switch-Case with Pattern matching and more.
  • 4.
    Replace complex macroswith functions or generics
  • 5.
    Replace complex macroswith functions ObjC ! NSLocalizedString(@"OK",@"a comment")
  • 6.
    Replace complex macroswith functions Swift ! NSLocalizedString("OK", comment:"comment")
  • 7.
    Replace complex macroswith functions #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) [bundle localizedStringForKey:(key) value:(val) table:(tbl)] ! // shorthand macros #define NSLocalizedString(key, comment) … #define NSLocalizedStringFromTable(key, tbl, comment) … !! ObjC ! NSLocalizedString(@"OK",@"a comment")
  • 8.
    Replace complex macroswith functions Swift ! // In Foundation Module: ! func NSLocalizedString(key: String, tableName: String? = default, bundle: NSBundle = default, value: String = default, #comment: String) -> String let str = NSLocalizedString("OK", comment:"comment")
  • 9.
    Functions - Defaultparameter values - External parameter name used when calling the function - Local parameter name available only in the function scope - Shorthand external parameter names - #comment let strError = NSLocalizedString("OK") // Error Type '(String, tableName: String?, bundle: NSBundle, value: String, comment: String)' does not conform to protocol 'StringLiteralConvertible' let str334 = NSLocalizedString("OK", "") // Error func NSLocalizedString(key: String, tableName: String? = default, bundle: NSBundle = default, value: String = default, #comment: String) -> String # Same external and local param name. Useful for global functions
  • 10.
    ! Methods -Functions associated with type “Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default.” class FooClass { func updateText(text: String, color: UIColor) -> String { return "(text) color:(color)" } } ! let fc = FooClass() fc.updateText("tlv", UIColor.blueColor()) ! ! fc.updateText("tlv", color: UIColor.blueColor()) //OK
  • 11.
    What you cando with your exiting complex macros • Replace the macros with C functions • Create ObjC wrapper class to implement/use the macros as functions. • Use Swift functions with defaults
  • 12.
    Closure "Function closurescapture local state variables! (Objects are state data with attached behavior;! Closures are behaviors with attached state data! and without the overhead of classes.)"! ! Peter Norvig
  • 13.
    ObjC - Blocks __block NSNumber *someVal = @10; // strong and mutable __weak typeof(self) weakSelf = self; ! [locationManager getCurrentLocationWithCompletion:^(CLLocation *location) { if (!location) { return; } ! if (weakSelf.completionBlock) { // Safer to use strongSelf in here weakSelf.completionBlock(location); } someVal = @20; }]; !
  • 14.
    ObjC - Blocks ! typedef void(^ PBUpdateLocationCompletion)(CLLocation * location); ! @property (copy, nonatomic) PBUpdateLocationCompletion completionBlock;
  • 15.
    var successHandler :((feed: Array) -> ())? var someValue = 1 ! successHandler = { feed in self.refreshFeed(feed) someValue = 2 } Swift - Closure
  • 16.
    request.successHandler = {[unowned self] feed in self.refreshFeed(feed) } Capture List
  • 17.
    Closure Factory Method Image Filter Example func blurFilter(radius: Int) -> (image: UIImage) -> (UIImage) { return { image in return BlurImage(image, radius) } } ! let blur20 = blurFilter(20) ! let blurredImage = blur20(image)
  • 18.
  • 19.
    class AddViewController :UIViewController { var didCancel : ((AddViewController) -> ())? var didFinish : ((AddViewController, name: String) -> ())? } class AddViewController : UIViewController { typealias CancelHandler = (AddViewController) -> () typealias FinishHandler = (AddViewController, name: String) -> () var didCancel : CancelHandler? var didFinish : FinishHandler? } Replace Delegate with Closures
  • 20.
    if let addVC= navigationVC.topViewController as? AddViewController { ! addVC.didCancel = { controller in self.dismissViewControllerAnimated(true, completion: nil) } addVC.didFinish = { controller, name in self.dismissViewControllerAnimated(true, completion: nil) self.addObjectWithName(name) } } Delegate with Closures
  • 21.
    Replace if -isEqual-elsewith switch-case and pattern matching
  • 22.
    Replace if-isEqual-else withswitch-case and pattern matching if ([segue.identifier isEqualToString:@"showDetails"]) { //… } else if ([segue.identifier isEqualToString:"add"]) { //… } ObjC
  • 23.
    Replace if-isEqual-else withswitch-case and pattern matching override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { if segue.identifier == "showDetail" { //... } else if segue.identifier == "add" { //.. } } Swift
  • 24.
    Replace if-isEqual-else withswitch-case and pattern matching override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { switch segue.identifier { case "showDetail": //… case "add": //… default: break } } Swift Switches support any kind of data and a wide variety of comparison operations.
  • 25.
    if let nvc= segue.destinationViewController as? UINavigationController { … } Replace if-isEqual-else with switch-case and pattern matching Optional binding that use optional down casting “Try to access viewController as a navigation controller. If this is successful, set a new temporary constant called nvc to the value stored in the returned optional UINavigationController.”
  • 26.
    Replace if-isEqual-else withswitch-case and pattern matching Another switch case pattern matching example override func prepareForSegue(segue: UIStoryboardSegue, sender: … { switch segue.destinationViewController { case let nvc as UINavigationController: … case let dvc as DetailsViewController: … default: break } }
  • 27.
  • 28.
    Results Enumeration andassociated value With NSErrorPointer (NSError?) var error : NSError? let url = NSURL(string: "http://www.apple.com") let data = NSData(contentsOfURL: url, options: NSDataReadingOptions.allZeros, error: &error) ! if let anError = error { println("failure: (anErrror.localizedDescription())" ) }
  • 29.
    Results Enumeration andassociated value Using Enums with associated value enum ServerResult { case Result (NSData) case Error (NSError) } ! let success = ServerResult.Result(data) ! let failure = ServerResult.Error(NSError(domain: "MyErrorDomain", code: 1, userInfo: nil)) switch success { case let .Result(data): let serverResponse = "Received data (data)" case let .Error(error): let serverResponse = "Failure... (error)" }
  • 30.
  • 31.
    Setting Defaults with?? operator ObjC !! NSString *name = text ? text : "default-name"; Swift var text : String? … ! ! let name = text ?? "default-name";
  • 32.
    CoreFoundation and otherC API Get free ARC!
  • 33.
    Swift compiler givesCoreFoundation, CoreGraphics and others ARC /* Shape */ let pathRef = CGPathCreateMutable() CGPathMoveToPoint(pathRef, nil, 0, 0) CGPathAddLineToPoint(pathRef, nil, 400, 0) CGPathAddLineToPoint(pathRef, nil, 400, 320) CGPathAddLineToPoint(pathRef, nil, 0, 320) CGPathAddLineToPoint(pathRef, nil, 0, 0) CGPathCloseSubpath(pathRef) !! // Compiler take care memory management in most cases So no need for these: CGPathRelease (pathRef) or CFRelease(pathRef)
  • 34.
    // In C ! CoreGraphic Structs CGRectMake(0, 0, 320, 480) ! // In swift - much more readable ! CGRect(x: 0, y: 0, width: 400, height: 320)
  • 35.
    GCD a bitmore cleaner
  • 36.
    GCD a bitmore cleaner let group = dispatch_group_create() dispatch_group_enter(group) dispatch_group_leave(group) dispatch_group_notify(group,dispatch_get_main_queue()) { … } ! dispatch_async(dispatch_get_main_queue()) { // trailing closure body } Type inferred, trailing closure
  • 37.
    Singleton : Replacedispatch_once with inner struct
  • 38.
    Singleton You canuse dispatch_once but we hope for better way class Singleton : NSObject { class var sharedInstance : Singleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! } override init() { println("yay"); } } ! Singleton.sharedInstance
  • 39.
    Singleton: Replace dispatch_oncewith inner struct Class variable currently not supported (xcode 6 beta 7) But structs do support static constants class Singleton : NSObject { class var sharedInstance : Singleton { struct Static { static let instance : Singleton = Singleton() } return Static.instance } override init() { println("yay"); } } Follow https://github.com/hpique/SwiftSingleton for updates
  • 40.
    References ! -Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/il/jEUH0.l - Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks. https://itun.es/il/1u3-0.l - WWDC 14 Swift videos (https://developer.apple.com/videos/wwdc/2014/) - Apple’s Dev Forums - https://github.com/hpique/SwiftSingleton
  • 41.
    Thank You NissanTsafrir @ntsafrir nissan@pixandbyte.com