Thinking in swift ppt

Post on 14-Apr-2017

55 views 1 download

transcript

Keith Moon - Senior iOS Developer

Thinking In Swift

MBLT.dev - MoscowNovember 2016

• iOS Developer since 2010• Worked with BBC News, Hotels.com and

Travelex• Working in Swift since it’s release• Built 2 apps end to end in Swift• “Swift 3 Cookbook” to be published by Pakt

Who am I?

@keefmoon

• Help users discover great local food• Make it quick and easy to order from a wide variety of

takeaways• Available on:

–Web–iOS–Android–Amazon Echo

What is Just Eat?

3

• Australia• Brazil• Canada• Denmark• France• Ireland• Italy• Mexico

What is Just Eat?

Global Business

• New Zealand• Norway• Spain• Switzerland• UK

• 12 iOS Developers• Organised around feature teams• Mixture of Objective-C and Swift• Regular releases• Multi-Variant Testing• Research team investigating new technology

What is Just Eat?

5

What is Just Eat?

• 12 iOS Developers• Organised around feature teams• Mixture of Objective-C and Swift• Regular releases• Multi-Variant Testing• Research team investigating new technology

Purpose of this talk?

• Swift is fundamentally different to Objective-C• Not just different syntax• Swift has more “tools in the toolbox”

How do we “think in Swift”?

How do we “think in Swift”?

• Use constructs that more closely match the model• Write code that is hard to use wrong• Remove the need for trivial tests• Consider a Protocol orientated approach

Structs

The right tool for the job

Class Objects

Enums

Protocols+ Extensions

Constrained Extensions

Tuples

The right tool for the job

Enums

• Integer based

• Typedef

• …and that’s it.

typedef enum : NSUInteger { JEPaymentOptionCash, JEPaymentOptionSavedCard, JEPaymentOptionApplePay, JEPaymentOptionAccountCredit } JEPaymentOption;

- (void)payByOption:(JEPaymentOption)option { // Pay ...}

The right tool for the job

Enums

• Based on any RawRepresentableenum PaymentOption: String { case cash case savedCard case applePay case accountCredit}

The right tool for the job

Enums

• Based on any RawRepresentable

• … or not.

enum PaymentOption { case cash case savedCard case applePay case accountCredit}

The right tool for the job

Enums

• Based on any RawRepresentable

• … or not.

• Associated Types

enum PaymentOption { case cash case savedCard(SavedCard) case applePay case accountCredit}

The right tool for the job

Enums

• Based on any RawRepresentable

• … or not.

• Associated Types

• Methods

enum PaymentOption { case cash case savedCard(SavedCard) case applePay case accountCredit

func canPay(at rest: Restaurant) -> Bool { //... }}

The right tool for the job

Enums

• Based on any RawRepresentable

• … or not.

• Associated Types

• Methods

• Computed variables

enum PaymentOption { case cash case savedCard(SavedCard) case applePay case accountCredit

func canPay(at rest: Restaurant) -> Bool { //... }

var isDeviceSupported: Bool { //... }}

Example App

Value Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

S

Value Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

SSearchFilter

postcode: BR13HPcuisine: nil

S

Value Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

SSearchFilter

postcode: BR13HPcuisine: Chicken

S

Value Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

S

Reference Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

C

Reference Type Semantics

SearchFilterpostcode: BR13HP

cuisine: nil

C

Reference Type Semantics

SearchFilterpostcode: BR13HPcuisine: Chicken

C

Reference Type Semantics

SearchFilterpostcode: BR13HPcuisine: Chicken

C

enum Cuisine: Int {

case american case bangladeshi //... case thai case turkish init?(string: String) { guard let index = Cuisine.stringValues.index(of: string), let cuisine = Cuisine(rawValue: index) else { return nil } self = cuisine } var displayString: String { return Cuisine.stringValues[rawValue] } private static var stringValues: [String] { return ["American", "Bangladeshi", //... "Thai", "Turkish"] }}

enum Cuisine: Int, CaseCountable { case american case bangladeshi //... case thai case turkish init?(string: String) { for index in 0..<Cuisine.caseCount { if let cuisine = Cuisine(rawValue: index), cuisine.displayString == string { self = cuisine return } } return nil } var displayString: String { return String(describing: self).capitalized }}

Cuisine Enum -

NewOld

restaurantService.fetchRestaurants(for: postcode) { [weak self] (fetchedRestaurants, error) in

if let fetchedRestaurants = fetchedRestaurants { self?.allRestaurants = fetchedRestaurants self?.visibleRestaurants = fetchedRestaurants self?.tableView.reloadData() } else if let error = error { // Handle Error print(error) }}

enum RestaurantResult { case success([Restaurant]) case failure(Error)}

restaurantService.fetchRestaurants(for: postcode) { [weak self] result in switch result { case .success(let fetchedRestaurants): self?.allRestaurants = fetchedRestaurants self?.visibleRestaurants = fetchedRestaurants self?.tableView.reloadData() case .failure(let error): // Handle Error print(error) }}

Networking Result -

New

Old

Reference Type Semantics

Margherita PizzaC

Vegetarian PizzaC

Coca-ColaC

SpriteC

Reference Type Semantics

Margherita PizzaC

Vegetarian PizzaC

Coca-ColaC

SpriteC

Discount

Reference Type Semantics

Margherita PizzaC

Vegetarian PizzaC

Coca-ColaC

SpriteC

Discount

Value Type Semantics

Margherita PizzaS

Vegetarian PizzaS

Vegetarian PizzaS

Coca-ColaS

Coca-ColaS

SpriteS

Value Type Semantics

Margherita PizzaS

Vegetarian PizzaS

Vegetarian PizzaS

Coca-ColaS

Coca-ColaS

SpriteS

Discount

Value Type Semantics

Margherita PizzaS

Vegetarian PizzaS

Vegetarian PizzaS

Coca-ColaS

Coca-ColaS

SpriteS

Discount

Summary

●Pick the appropriate Swift type for the concept being

modelled

●Consider the Type semantics

●Defining behaviours as protocols can produce expressive

code

●Avoid “Stringly” typed implementations

●Try to anticipate and prevent future developer errors

Thanks! @keefmoonkeith.moon@just-eat.com

keefmoon