swift - one step forward from obj-c
TRANSCRIPT
![Page 1: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/1.jpg)
Swift - One Step Forward from ObjC
Nissan Tsafrir // @ntsafrir // { Pix & Byte }
www.pixandbyte.com
![Page 2: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/2.jpg)
Swift Fast . Modern . Safe . Interactive
![Page 3: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/3.jpg)
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.
![Page 4: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/4.jpg)
Replace complex macros with functions or generics
![Page 5: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/5.jpg)
Replace complex macros with functions
ObjC !
NSLocalizedString(@"OK",@"a comment")
![Page 6: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/6.jpg)
Replace complex macros with functions
Swift !
NSLocalizedString("OK", comment:"comment")
![Page 7: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/7.jpg)
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")
![Page 8: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/8.jpg)
Replace complex macros with functions
!// In Foundation Module:
!func NSLocalizedString(key: String, tableName: String? = default, bundle:
NSBundle = default, value: String = default, #comment: String) -> String
Swift
let str = NSLocalizedString("OK", comment:"comment")
![Page 9: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/9.jpg)
Type '(String, tableName: String?, bundle: NSBundle, value: String, comment: String)' does not conform to protocol 'StringLiteralConvertible'
let strError = 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
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 str334 = NSLocalizedString("OK", "") // Error
![Page 10: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/10.jpg)
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
!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.”
![Page 11: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/11.jpg)
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
![Page 12: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/12.jpg)
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
![Page 13: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/13.jpg)
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; }]; !
![Page 14: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/14.jpg)
!typedef void(^ PBUpdateLocationCompletion)(CLLocation * location); !@property (copy, nonatomic) PBUpdateLocationCompletion completionBlock;
ObjC - Blocks
![Page 15: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/15.jpg)
var successHandler : ((feed: Array) -> ())? var someValue = 1 !successHandler = { feed in self.refreshFeed(feed) someValue = 2 }
Swift - Closure
![Page 16: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/16.jpg)
request.successHandler = { [unowned self] feed in self.refreshFeed(feed) }
Capture List
![Page 17: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/17.jpg)
func blurFilter(radius: Int) -> (image: UIImage) -> (UIImage) { return { image in return BlurImage(image, radius) } } !let blur20 = blurFilter(20) !let blurredImage = blur20(image)
Closure Factory Method
Image Filter Example
![Page 18: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/18.jpg)
Replace Delegate with Closures
![Page 19: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/19.jpg)
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
![Page 20: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/20.jpg)
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
![Page 21: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/21.jpg)
Replace if -isEqual-else with switch-case and pattern matching
![Page 22: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/22.jpg)
if ([segue.identifier isEqualToString:@"showDetails"]) { //… } else if ([segue.identifier isEqualToString:"add"]) { //… }
Replace if-isEqual-else with switch-case and pattern matching
ObjC
![Page 23: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/23.jpg)
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { if segue.identifier == "showDetail" { //... } else if segue.identifier == "add" { //.. } }
Replace if-isEqual-else with switch-case and pattern matching
Swift
![Page 24: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/24.jpg)
override func prepareForSegue(segue: UIStoryboardSegue, sender: …) { switch segue.identifier { case "showDetail": //… case "add": //… default: break } }
Replace if-isEqual-else with switch-case and pattern matching
Swift
Switches support any kind of data and a wide variety of comparison operations.
![Page 25: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/25.jpg)
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.”
![Page 26: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/26.jpg)
override func prepareForSegue(segue: UIStoryboardSegue, sender: … { switch segue.destinationViewController { case let nvc as UINavigationController: … case let dvc as DetailsViewController: … default: break }
}
Replace if-isEqual-else with switch-case and pattern matching
Another switch case pattern matching example
![Page 27: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/27.jpg)
Error Reporting
![Page 28: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/28.jpg)
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
With NSErrorPointer (NSError?)
![Page 29: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/29.jpg)
enum ServerResult { case Result (NSData) case Error (NSError) } !let success = ServerResult.Result(data) !let failure = ServerResult.Error(NSError(domain: "MyErrorDomain", code: 1, userInfo: nil))
Results Enumeration and associated value
switch success { case let .Result(data): let serverResponse = "Received data \(data)" case let .Error(error): let serverResponse = "Failure... \(error)" }
Using Enums with associated value
![Page 30: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/30.jpg)
Setting Defaults with ?? operator
![Page 31: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/31.jpg)
ObjC !!
NSString *name = text ? text : "default-name";
Swift var text : String? … !!let name = text ?? "default-name";
Setting Defaults with ?? operator
![Page 32: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/32.jpg)
CoreFoundation and other C API Get free ARC!
![Page 33: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/33.jpg)
/* 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)
Swift compiler gives CoreFoundation, CoreGraphics and others ARC
![Page 34: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/34.jpg)
// In C ! CGRectMake(0, 0, 320, 480) !// In swift - much more readable ! CGRect(x: 0, y: 0, width: 400, height: 320)
CoreGraphic Structs
![Page 35: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/35.jpg)
GCD a bit more cleaner
![Page 36: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/36.jpg)
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
![Page 37: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/37.jpg)
Singleton : Replace dispatch_once with inner struct
![Page 38: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/38.jpg)
Singleton
You can use dispatch_once but we hope for better wayclass 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
![Page 39: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/39.jpg)
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
![Page 40: Swift - One step forward from Obj-C](https://reader033.vdocument.in/reader033/viewer/2022042906/589c3a501a28abec478b59fb/html5/thumbnails/40.jpg)
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