Cocoa Design Patterns in Swift
-
Upload
micheletitolo -
Category
Technology
-
view
2.591 -
download
0
description
Transcript of Cocoa Design Patterns in Swift
Cocoa Design Patternsin Swift@MicheleTitolo
• New language features
• Functional patterns
• Patterns in Swift
• Anti-patterns
What we’ll cover
New language features
Tuples
Tuples group multiple values into a single compound value.
let http404Error = (404, "Not Found")println(http404Error.0)
var http200Response: (statusCode: Int, statusText: String, hasBody: Bool)
http200Response.statusCode = 200http200Response.statusText = "OK"http200Response.hasBody = true
You can put any kind of object in a tuple
Generics
<T>
More than just an id
Abstraction
Create functions without declaring type
struct Stack<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() }}
<T: Equitable>
AnyObject
...used a lot more like id
Closures
“Closures are behaviors with attached state”
- Peter Norvig
Like blocks, but better!
var closure = { (params) -> returnType in statements}
let
Immutable variable
var myString: String? = someFucntion()
if let greeting = myString { println(greeting)}else { println("Not a string") }
Structs + Enums
Structs:Pass-by-value
struct Rect { var origin: Point var size: Size}
Structs can have methods, and conform to protocols
Enums:also pass-by-value
Also can conform to protocols and have methods
enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func description() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.toRaw()) } }}
Functional Patterns
Function Passing
func printExcitedly(string: String){ println(string + "!!!!!!!")}
var excitedFunc = printExcitedly
Pass functions into functions
func printVeryExcitedly(excitedFunction: (String) -> Void, message: String){
excitedFunction(message.uppercaseString)}
printVeryExcitedly(printExcitedly, "Hello");
Return functions from functions
func beExcited(excitementLevel: Int) -> (String) -> Void { ...}
Patterns
Composition
...because we can pass functions!
The OO way
class Car { let numWheels: Int let numCylinders: Int init (numWheels: Int, numCylinders: Int) { self.numWheels = numWheels self.numCylinders = numCylinders }}
var newCar = Car(numWheels: 4,numCylinders: 4)var otherCar = Car(numWheels: 4, numCylinders: 6)
var motorcycle = ??
class Motorcycle { ...}
This is not ideal
protocol Vehicle { var numWheels: Int {get set} var numCylinders: Int {get set} func drive()}
Better
How do we handle this at scale?
struct WheelSet { var wheelSize: Int var wheelFrictionCoefficient: Float}
struct BodyType { var numWheels: Int var wheels: WheelSet var wheelBase: Float}
enum EngineType: Int { case Automatic, Manual}
protocol Vehicle { var body: BodyType {get set} var transmission: EngineType {get set} func drive(force: Float) func turn(speed: Float)}
Better
...but we can still improve
Factories
Abstract away objectcreation and composition
protocol VehicleCreator { func createVehicle(bodyType: BodyType, engineType: EngineType) -> Vehicle}
class VehicleFactory: VehicleCreator { func createVehicle(bodyType: BodyType, engineType: EngineType) -> Vehicle {}}
protocol VehicleCreator { func createVehicle(bodyType: BodyType, engineType: EngineType) -> Vehicle}
class VehicleFactory: VehicleCreator { func createVehicle(bodyType: BodyType, engineType: EngineType) -> Vehicle {}}
class MotorcycleFactory: VehicleCreator { func createVehicle(bodyType: BodyType, engineType: EngineType) -> Vehicle {}}
This still looks very OO
class VehicleFactory { func wheelSetGenerator(wheelSize: Int, friction: Float) -> WheelSet { return WheelSet(wheelSize: wheelSize, wheelFrictionCoefficient: friction) } func generateBodyType(wheelCount: Int, wheelType: WheelSet, wheelBase: Float) -> (Void) -> BodyType { func bodyGen() -> BodyType { return BodyType(numWheels:wheelCount, wheels:wheelType, wheelBase:wheelBase) } return bodyGen } func createVehicle( bodyGenerator:(wheelCount: Int, wheelType: WheelSet, wheelBase: Float) -> BodyType, transmission: EngineType) -> Vehicle {}}
let factory: VehicleFactory = VehicleFactory()let motorcycleWheelSet: WheelSet = factory.wheelSetGenerator(28, friction: 0.5)let motorcycleBodyGen = factory.generateBodyType(2, wheelType:motorcycleWheelSet, wheelBase: 45)let motorcycle = factory.createVehicle(motorcycleBodyGen, transmission: .Manual)let electricMotorcycle = factory.createVehicle(motorcycleBodyGen, transmission: .Auomatic)
Factories in Swift can be incredibly flexible
Command
A delegate chainthat returns a function
protocol Commander { func commandSomething(String) -> (Int) -> Dictionary<String, String>}
class ViewController: { let delegate: Commander}
Why is this better than closures?
It’s more explicit
It’s more flexible
Enumeration
Not the type enum!
We have new ways of transforming collections
[1,2,3,4].map { (var number) -> Int in return number * number}
var array = [3, 2, 5, 1, 4]array.sort { $0 < $1 }
let array = [1, 2, 3, 4, 5]let reversedArray = array.reverse()// reversedArray = [5, 4, 3, 2, 1]
And of course, this is useful for more than just math
var vehicles = [suv, motorcycle, electricMotorcycle, car, truck]var manualVehicles = vehicles.filter { (var vehicle: Vehicle) -> Vehicle in return (vehicle.transmission == .Manual) }// manualVehicles = [motorcycle, truck]
Encapsulate better
func meanMedianMode(a: Array<Int>) -> (mean:Int, median:Int, mode:Int) { var mean = findMean(a) var median = findMedian(a) var mode = findMode(a) return (mean, median, mode)}
Tuples with names are incredibly useful
Anti-Patterns
No changes to handling protocols
This is the slide I was hoping to put something magical on
class ViewController: UIViewController, UITableViewDataSource { var tableView: UITableView func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell if (cell == nil) { cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell") } cell.textLabel.text = "Hello World" return cell } func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return 1 }}
Protocols are first class citizens in Swift, just like in Obj-c
Tuples all the way down
Yes, you can put a tuple in a tuple
These are temporary data structures
We have better OO tools available
Operator overloading
Don’t overload default operators
func decode(json: JSON) -> User? { return _JSONObject(json) >>> { d in User.create <^> d["id"] >>> _JSONInt <*> d["name"] >>> _JSONString <*> d["email"] >>> _JSONString }}
Operators make code harder to read
Type is still important
Getting classes from AnyObject are kind of a pain
Still be explicit when you can
var music: [String: String] = ["AC/DC": "Hells Bells", "Red Hot Chili Peppers": "Californication"]
In Summary
Swift gives us new tools
But Objective-C, and its patterns, aren’t going away
anytime soon
• Today 11:30amInteroperating Swift with Lower Level Code by Stephan Tramer in Terrace
• Tomorrow 1:45pm Functional Programming in Swift by Chris Eidhof in Vail
More Swift!
• Swift Programming Guide from Apple
• Design Patterns in Dynamic Programming by Peter Norvig
• Erica Sadun’s many blog posts on Swift
• Functional Programming in Swift, ebook by Objc.io founders (See Chris’ talk tomorrow!)
• Instance Methods and Curried Functions in Swift by Ole Begemann
Resources
Thanks!@MicheleTitolo