Adopting Swift Generics
-
Upload
max-sokolov -
Category
Technology
-
view
156 -
download
0
Transcript of Adopting Swift Generics
Adopting Swift GenericsПерейдем на <T>
Max Sokolov - iOS dev @ [email protected] max_sokolov
2
3
World’s 3rdBiggest
Classifieds Site
35musers
per month
500kitems
per day
100kdeals
Agenda
• Dynamic type-casting problem
• Generics in Swift
• Protocols with associated types
• Declarative type-safe UIKit
• Livecoding!
4
🤔
class Matrix<T: Choiceable where T.T == T, T: Learnable, T: Fateable>
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
😎
Segmentation fault: 11
Why?
• One team of 5 people
• 3 different apps with shared components (mostly Swift)
• 20 private CocoaPods
• Large code base (~100k)
10
[go back];
Typical api request
API Resource /users
Raw DataNSData?
Parsed Object[String: String]?
ModelUser?
Request Parsing
ObjectMapper
12
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
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
RUN TIME!
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
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
<T>
Demo
UIKit<T>?
UITableView powered by generics
90% of our screens are table views
23
Problems with UITableView
• Boilerplate
• Painful when data sources are complex and dynamic
• Not type safe (dequeueReusableCellWithIdentifier etc.)
24
What table view actually needs?
Model ViewModel
UITableViewCell
Deadline ;)
25
<ItemType, CellType>
What if…
Line of code
let row = TableRow<String, MyTableViewCell>(item: "string")
28
Demo
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
Functional programming
The power of declarative approach
let rows: [Row] = strings.map { TableRow<String, MyTableViewCell>(item: $0) }
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) })
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
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
AvitoTechhttps://twitter.com/avitotech
THANK YOU!
QUESTIONS?
Max Sokolov - iOS dev @ Avito
max_sokolovhttps://github.com/maxsokolov