54
Ash Furrow, Artsy Lessons from Production Swift

ITT 2015 - Ash Furrow - Lessons from Production Swift

Embed Size (px)

Citation preview

Ash Furrow, Artsy

Lessonsfrom

Production Swift

February, 2014

SwiftLet’s talk about

1. The Need for Swift

2. The Fast and the Faulty

3. Seek Out Bold New Worlds

Need

SwiftThe

for

Objective-C

STAA TEMP ;store the A value in TEMP TXS ;push return address back onto stack LDY #$00 ;load Y with zero - will hold result LOOP1 LDAA TEMP ;load A into TEMP ANDA MASK ;AND A with Mask BNE ADD1 BRA NONE1 ADD1 INY ;increment our counter of 1's NONE1 LDAA TEMP ;reload accumulator A LSL MASK ;Shift the mask's 1 bit left BNE LOOP1 ;If we haven't finished our loop, branch LDAA #$01 ;load new mask into A STAA MASK ;store the reset mask into MASK TSX ;pull of return address and store in X PULA ;pull off A STAA TEMP ;store the value into temp TXS ;push return address back onto the stack LOOP2 LDAA TEMP ;Load A into TEMP ANDA MASK ;logical AND MASK with A BNE ADD2 ;add one if we need to BRA NONE2 ADD2 INY ;increment our counter of 1's NONE2 LDAA TEMP LSL MASK ;shift our mask left by one BNE LOOP2 ;loop back until we've exhausted positions STY TEMP ;store Y into TEMP - this is the number of 1's LDAB TEMP ;load the number of 1's into B LDAA #$10 ;load dec 16 into A SBA ;A - B -> A same as 16 - B -> A STAA TEMP ;this is now the number of zeros

—John Siracusa

“While hardware performance increases over time, the human capacity to deal with complexity does not.”

StuckObjective-C

Past

is

in the

Beyond Hope

Objective-Cis

Criteria1. No C baggage

2. Memory Managed

3. Native unicode strings

4. Native collections

5. Be concise

6. Named Parameters

Criteria1. No C baggage

2. Memory Managed

3. Native unicode strings

4. Native collections

5. Be concise

6. Named Parameters

😋

😅

😃

😄

😍

😎

The Need for Swift

• Programming abstraction increases over time

• Objective-C has improved all it can

• Swift is the next step

• Revolution, not evolution

Fast

FaultyThe

and the

Problems In Beta

• Xcode crashes

• Compiler segfaults

• Constant changes to Swift

• Many language limitations

Problems Now

• Still some stability issues

• Still frequent changes to Swift

• Still some remaining language limitations

Problems Now

• Language changes tied to Xcode versions

• Runtime changes tied to Xcode versions

• Changes in resource-loading in frameworks

Community Tools

• Most still in their infancy

• CocoaPods, Jazzy, SBConstants…

• The rest do not exist

• Test coverage analyzer

Community Libraries

• Struggling to accomodate frequent Swift changes

• Xcode updates make this difficult

The Fast and the Faulty

• Swift had a rough start

• Was to be expected

• Things are better now

• Mostly

• Growing pains

Seek Out

New WorldsBold

Problem Solving in Objective-C

Problem Solving in Swift

is not

Examples

Index Paths

• Used to identify cells in a table view

• Section, row

• Lots of horrendous code

• It’s so bad

• Seriously bad

Index Pathsif (indexPath.section == 0) { if (indexPath.row == 0) {

} else if (indexPath.row == 1) { } else if ...} else if (indexPath.section == 1) { if (indexPath.row == 0) {

} else if (indexPath.row == 1) { } else if ...} else if ...

Index Pathsif (indexPath.section == 0) { if (indexPath.row == 0) {

} else if (indexPath.row == 1) { } else if ...} else if (indexPath.section == 1) { if (indexPath.row == 0) {

} else if (indexPath.row == 1) { } else if ...} else if ...

Index Paths

switch (indexPath.section, indexPath.row) {case (0, 0):case (0, 1):case (1, 0):case (1, 1):default: // nop}

Still TerribleThis is

Index Pathsswitch (indexPath.section, indexPath.row) {case (0, let row): // Executed for any section 0, row is rowcase (let section, 0) where section % 2 == 1: // Executed for first rows of odd all sectionscase (let section, let row) where validate(section): // Executed when validate() returns truedefault: // Executed on all other cases}

Generics

• Define functions, structs, others in the abstract

• Create one instead of many

• Arrays, dictionaries, and sets are all generics

Genericsstruct Stack<T> { private var contents = Array<T>()

mutating func push(value: T) { contents.insert(value, atIndex: 0) }

mutating func pop() -> T { return contents.removeAtIndex(0) }

var isEmpty: Bool { return countElements(contents) == 0 }}

Generics

var intStack = Stack<Int>()var stringStack = Stack<String>()var stackStack = Stack<Stack<AnyObject>>()

intStack.push(1)intStack.pop() // Returns 1

Lazy Loading

• Create resource when it is first accessed

• Avoids unnecessary work for CPU

• Avoids unnecessary memory use

Lazy Objective-C

• No language-level support

• Lots of repetition

• Tedious work

• Lots of repetition

Lazy Objective-C@interface MyClass: NSObject

@property (nonatomic, strong) Name *name;

@end

@implementation

- (Resource *)resource { if (_resource == nil) { _resource = "Ash Furrow"; }

return _resource}

@end

Lazy Swift

class MyClass { lazy var name = "Ash Furrow"}

Lazy Swift

class MyClass { lazy var name = "Ash Furrow"}

MyClass().name // Returns "Ash Furrow"

let instance = MyClass()instance.name = "Orta Therox"instance.name // Returns “Orta Therox"

Lazy Swiftclass MyClass { lazy var name = "Ash Furrow” lazy var greeting: String = { return "Hello, \(self.name)" }()}

MyClass().greeting // Returns "Hello, Ash Furrow"

let instance = MyClass()instance.name = "Orta Therox"instance.greeting // Returns "Hello, Orta Therox"instance.name = "Eloy Durán"instance.greeting // Returns "Hello, Orta Therox"

Extending Types

• Objective-C has “categories” for extending existing classes

• Swift has “extensions” instead

• They work on all types

Extending Typesextension Int { func times(closure: () -> ()) { for i in 0..<self { closure() } }}

4.times { // Do something 4 times}

Extending Typesextension Int { var hours: NSTimeInterval { return NSTimeInterval(3600 * self) }}

extension NSTimeInterval { var fromNow: NSDate { return NSDate(timeIntervalSinceNow: self) } var ago: NSDate { NSDate(timeIntervalSinceNow: -self) }}

4.hours.fromNow4.hours.ago

Functional Awesomenesslet people = ["Carter", "Sebastian", "Daniel"]people.map { "Hello, \($0)!" }

func hello(name: String) -> String { return "Hello, \(name)!"}

people.map(hello)

or…

Functional Awesomeness

func say(greeting: String) -> (name: String) -> String { return { (name: String) -> String in "(greeting), \(name)!" }}

people.map(say("Hello"))people.map(say("Merhaba"))

Functional Awesomeness

func say(greeting: String)(name: String) -> String { return "(greeting), \(name)!"}

people.map(say("Hello"))people.map(say("Merhaba"))

SBConstants

• Generate constants for Storyboard identifiers

• Compile-time checked enum

• Can be extended…

SBConstants

func performSegue(identifier: SegueIdentifier) { performSegueWithIdentifier(identifier.rawValue, sender: self)}

...

func ==(lhs: UIStoryboardSegue, rhs: SegueIdentifier) -> Bool { return lhs.identifier == rhs.rawValue}

SBConstants

peformSegue(.RegisterCreditCard)

...

func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue == .RegisterCreditCard { ... }}

SBConstants

• Don’t use rawValue all over the place

• Abstract it away

• Get compile-time safety

Familiar Problems

New Ways

to solve

Let’s look for

For Advice

Askother communities

Let’s

Resources

• Natasha the Robot’s newsletter

• iOSDevWeekly

• iOS Goodies

• GitHub Explore

• leanpub.com/yourfirstswiftapp

Eidolon

1. The Need for Swift

2. The Fast and the Faulty

3. Seek Out Bold New Worlds

Better Mistakes

Make

Tomorrow