41
Swift - One Step Forward from ObjC Nissan Tsafrir // @ntsafrir // { Pix & Byte } www.pixandbyte.com

Swift - One step forward from Obj-C

Embed Size (px)

Citation preview

Page 1: Swift -  One step forward from Obj-C

Swift - One Step Forward from ObjC

Nissan Tsafrir // @ntsafrir // { Pix & Byte }

www.pixandbyte.com

Page 2: Swift -  One step forward from Obj-C

Swift Fast . Modern . Safe . Interactive

Page 3: Swift -  One step forward from Obj-C

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

Replace complex macros with functions or generics

Page 5: Swift -  One step forward from Obj-C

Replace complex macros with functions

ObjC !

NSLocalizedString(@"OK",@"a comment")

Page 6: Swift -  One step forward from Obj-C

Replace complex macros with functions

Swift !

NSLocalizedString("OK", comment:"comment")

Page 7: Swift -  One step forward from Obj-C

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

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

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

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

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

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

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

!typedef void(^ PBUpdateLocationCompletion)(CLLocation * location); !@property (copy, nonatomic) PBUpdateLocationCompletion completionBlock;

ObjC - Blocks

Page 15: Swift -  One step forward from Obj-C

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

request.successHandler = { [unowned self] feed in self.refreshFeed(feed) }

Capture List

Page 17: Swift -  One step forward from Obj-C

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

Replace Delegate with Closures

Page 19: Swift -  One step forward from Obj-C

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

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

Replace if -isEqual-else with switch-case and pattern matching

Page 22: Swift -  One step forward from Obj-C

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

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

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

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

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

Error Reporting

Page 28: Swift -  One step forward from Obj-C

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

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

Setting Defaults with ?? operator

Page 31: Swift -  One step forward from Obj-C

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

CoreFoundation and other C API Get free ARC!

Page 33: Swift -  One step forward from Obj-C

/* 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

// 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

GCD a bit more cleaner

Page 36: Swift -  One step forward from Obj-C

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

Singleton : Replace dispatch_once with inner struct

Page 38: Swift -  One step forward from Obj-C

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

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

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

Page 41: Swift -  One step forward from Obj-C

Thank You

Nissan Tsafrir

@ntsafrir

[email protected]