adopting swift generics

39
Adopting Swift Generics Перейдем на <T> Max Sokolov - iOS dev @ Avito [email protected] max_sokolov

Upload: max-sokolov

Post on 24-Jan-2017

156 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Adopting Swift Generics

Adopting Swift GenericsПерейдем на <T>

Max Sokolov - iOS dev @ [email protected] max_sokolov

Page 2: Adopting Swift Generics

2

Page 3: Adopting Swift Generics

3

World’s 3rdBiggest

Classifieds Site

35musers

per month

500kitems

per day

100kdeals

Page 4: Adopting Swift Generics

Agenda

• Dynamic type-casting problem

• Generics in Swift

• Protocols with associated types

• Declarative type-safe UIKit

• Livecoding!

4

Page 5: Adopting Swift Generics

🤔

class Matrix<T: Choiceable where T.T == T, T: Learnable, T: Fateable>

Page 6: Adopting Swift Generics

Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.

Apple docs

What for?

6

Page 7: Adopting Swift Generics

😎

Page 8: Adopting Swift Generics

Segmentation fault: 11

Page 9: Adopting Swift Generics
Page 10: Adopting Swift Generics

Why?

• One team of 5 people

• 3 different apps with shared components (mostly Swift)

• 20 private CocoaPods

• Large code base (~100k)

10

Page 11: Adopting Swift Generics

[go back];

Page 12: Adopting Swift Generics

Typical api request

API Resource /users

Raw DataNSData?

Parsed Object[String: String]?

ModelUser?

Request Parsing

ObjectMapper

12

Page 13: Adopting Swift Generics

Implementation@implementation DataProvider

- (void)fetch:(NSString *)resources mappingClass:(Class)mappingClass completion:(void(^)(NSArray<id<Mappable>> *results))completion { // Load data... // Parse data...

if ([mappingClass conformsToProtocol:@protocol(Mappable)]) { id result = [mappingClass initWithDictionary:response]; completion(@[result]); } }

@end

13

Page 14: Adopting Swift Generics

The problem?@implementation DataProvider

- (void)fetch:(NSString *)resources mappingClass:(Class)mappingClass completion:(void(^)(NSArray<id<Mappable>> *results))completion { // Load data... // Parse data...

if ([mappingClass conformsToProtocol:@protocol(Mappable)]) { id result = [mappingClass initWithDictionary:response]; completion(@[result]); } }

@end

14

Page 15: Adopting Swift Generics

RUN TIME!

Page 16: Adopting Swift Generics

What run time means?

DataProvider *provider = [DataProvider new]; [provider fetch:@"/users" mappingClass:[NSString class] // compiler doesn’t warn you here... completion:^(NSArray<User *> *results) { }];

16

Page 17: Adopting Swift Generics

You are doing it wrong with Swift

let dataProvider = DataProvider() dataProvider.fetch("/resource", mappingClass: User.self) { result in // code smell... guard let users = result.values as? [User] else { return } }

17

Page 18: Adopting Swift Generics

<T>

Page 19: Adopting Swift Generics

Demo

Page 20: Adopting Swift Generics

UIKit<T>?

Page 21: Adopting Swift Generics

UITableView powered by generics

Page 22: Adopting Swift Generics

90% of our screens are table views

Page 23: Adopting Swift Generics

23

Page 24: Adopting Swift Generics

Problems with UITableView

• Boilerplate

• Painful when data sources are complex and dynamic

• Not type safe (dequeueReusableCellWithIdentifier etc.)

24

Page 25: Adopting Swift Generics

What table view actually needs?

Model ViewModel

UITableViewCell

Deadline ;)

25

Page 26: Adopting Swift Generics

<ItemType, CellType>

Page 27: Adopting Swift Generics

What if…

Page 28: Adopting Swift Generics

Line of code

let row = TableRow<String, MyTableViewCell>(item: "string")

28

Page 29: Adopting Swift Generics

Demo

Page 30: Adopting Swift Generics

TableKitOpen Source

https://github.com/maxsokolov/TableKit

🚀

Page 31: Adopting Swift Generics

TableKit

import TableKit

let clickAction = TableRowAction<String, MyTableViewCell>(.click) { (data) in }

let row = TableRow<String, MyTableViewCell>(item: "string", actions: [clickAction])

tableDirector += TableSection(rows: [row])

31

Page 32: Adopting Swift Generics

Functional programming

Page 33: Adopting Swift Generics

The power of declarative approach

let rows: [Row] = strings.map { TableRow<String, MyTableViewCell>(item: $0) }

Page 34: Adopting Swift Generics

The view layer is simply a mapping of our data layer

let rows: [Row] = users .filter({ $0.active }) .map({ UserViewModel(user: $0) }) .map({ TableRow<UserViewModel, UserTableViewCell>(item: $0) })

Page 35: Adopting Swift Generics

Resume• Currently, SDK/API’s are not generic

• Compiler is not perfect

• Can’t be used with Objective-C

• Compile-time type-safety help to know about potential issues earlier

• We could build great, flexible, easy to use API’s

35

Page 36: Adopting Swift Generics

Links

36

Covariance and Contravariancehttps://www.mikeash.com/pyblog/friday-qa-2015-11-20-covariance-and-contravariance.html

Protocols with Associated Types, and How They Got That Wayhttp://www.slideshare.net/alexis_gallagher/protocols-with-associated-types-and-how-they-got-that-way

Why Associated Types?http://www.russbishop.net/swift-why-associated-types

TableKithttps://github.com/maxsokolov/TableKit

Page 37: Adopting Swift Generics

AvitoTechhttps://twitter.com/avitotech

Page 38: Adopting Swift Generics

THANK YOU!

Page 39: Adopting Swift Generics

QUESTIONS?

Max Sokolov - iOS dev @ Avito

max_sokolovhttps://github.com/maxsokolov