Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
面向协议编程与 Cocoa 的邂逅
Search
Wei Wang
September 24, 2016
Technology
14
4.6k
面向协议编程与 Cocoa 的邂逅
My talk in MDCC 16. About using Protocol-Oriented Programming language in daily Cocoa life.
Wei Wang
September 24, 2016
Tweet
Share
More Decks by Wei Wang
See All by Wei Wang
網路之難,難於上青天 - iPlayground 2019
onevcat
11
4.7k
GMTC 2019 - 在分歧中发展,2019 我们能用 Swift 做什么
onevcat
0
820
从 Swift 到机器学习
onevcat
2
870
iOS Dev - The Dark Side
onevcat
0
110
Swift 3 - From Expert to Beginner
onevcat
2
200
如何打造一个让人愉快的框架
onevcat
4
22k
JSPatch Introduction
onevcat
0
180
Objective-C Runtime Swizzle
onevcat
0
160
Unity Memory
onevcat
0
120
Other Decks in Technology
See All in Technology
GoとアクターモデルでES+CQRSを実践! / proto_actor_es_cqrs
ytake
1
160
MySQLのロックの種類とその競合
yoku0825
6
1.6k
開発と事業を繋ぐ!SREのオブザーバビリティ戦略 ~ Developers Summit 2024 Summer ~
leveragestech
0
630
LLMアプリケーションの評価の実践と課題 ~PharmaXにおける今後の展望~
pharma_x_tech
2
160
VPoEの視点から見た、ヘンリーがサーバーサイドKotlinを使う理由 / Why Server-side Kotlin 2024
cho0o0
1
420
[NIKKEI Tech Talk] KDDI/KAG Scrum & Community for Engineering Training
curanosuke
2
220
E2Eテスト自動化プラットフォームにおけるAIの活用
shift_evolve
0
190
AutomatedLabを使って内部ペンテストを勉強しよう! -やられ社内ネットワークの自動構築-
n_etupirka
1
610
20240725 LLMによるDXのビジョンと、今何からやるべきか @Azure OpenAI Service Dev Day
nrryuya
3
1.2k
推薦システムを本番導入する上で一番優先すべきだったこと~NewsPicks記事推薦機能の改善事例を元に~
morinota
0
130
頼られるのが大好きな 皆さんへ - 支援相手との期待の合わせ方、突き放し方 -/For_people_who_like_to_be_relied_on
naitosatoshi
1
290
サービスの持続的な成長と技術負債について
siva_official
PRO
10
4.4k
Featured
See All Featured
Building Applications with DynamoDB
mza
89
5.8k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
360
22k
Designing the Hi-DPI Web
ddemaree
276
34k
GraphQLとの向き合い方2022年版
quramy
36
13k
Design by the Numbers
sachag
277
18k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
19k
VelocityConf: Rendering Performance Case Studies
addyosmani
321
23k
How GitHub (no longer) Works
holman
305
140k
The Art of Programming - Codeland 2020
erikaheidi
48
13k
WebSockets: Embracing the real-time Web
robhawkes
59
7.2k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
277
13k
A better future with KSS
kneath
231
17k
Transcript
ᶎݻܐᦓᖫᑕӨ Cocoa ጱᮁᭊ MDCC 16 ሴ - 2016 ଙ 9
์ 24 ෭
Ԇ᷌ • ᩸ɾॳᦩ • ಥɾ૬ • ɾᅾ • ݳɾജ
Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬ •
ɾᅾ • ݳɾജ
Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬ -
ܐᦓಘᶎݻܐᦓᖫᑕ • ɾᅾ • ݳɾജ
Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬ -
ܐᦓಘᶎݻܐᦓᖫᑕ • ɾᅾ - ࣁ෭ଉݎӾֵአܐᦓ • ݳɾജ
Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬ -
ܐᦓಘᶎݻܐᦓᖫᑕ • ɾᅾ - ࣁ෭ଉݎӾֵአܐᦓ • Model (Networking) • ViewController • ݳɾജ
᩸ɾॳᦩ Ջԍฎ Swi% ܐᦓ Protocol
protocol Greetable { var name: String { get } func
greet() }
ᶎݻ Object-oriented
ᶎݻ class Animal { var leg: Int { return 2
} func eat() { print("eat food.") } func run() { print("run with \(leg) legs") } } class Tiger: Animal { override var leg: Int { return 4 } override func eat() { print("eat meat.") } } let tiger = Tiger() tiger.eat() // "eat meat" tiger.run() // "run with 4 legs"
ViewController → UIViewController class ViewCotroller: UIViewController { // ᖀಥ //
view, isFirstResponder()... // ෛے func myMethod() { } }
AnotherViewController → UITableViewController → UIViewController class AnotherViewController: UITableViewController { //
ᖀಥ // tableView, isFirstResponder()... // ෛے func myMethod() { } }
ࢯहԏӞ Cross-Cu'ng Concerns ཞڔىဳᅩ
ᥴ٬ොໜ • Copy & Paste • ف BaseViewController • ׁᩢဳف
• ग़ᖀಥ
Objec&ve-C Message Sending
ViewController *v1 = ... [v1 myMethod]; AnotherViewController *v2 = ...
[v2 myMethod];
NSArray *array = @[v1, v2]; for (id obj in array)
{ [obj myMethod]; }
NSObject *v3 = [NSObject new] // v3 ဌํਫሿ `myMethod` NSArray
*array = @[v1, v2, v3]; for (id obj in array) { [obj myMethod]; } // Runtime error: // unrecognized selector sent to instance blabla
ࢯहԏԫ Dynamic Dispatch Safety ۖாၝݎਞق
OOP ࢯह • ۖாၝݎਞق • ཞڔىဳᅩ
ܐᦓ Protocol
Java, C# Interface
Swift protocol
Swi$ protocol protocol Greetable { var name: String { get
} func greet() }
Swi$ protocol protocol Greetable { var name: String { get
} func greet() } struct Person: Greetable { let name: String func greet() { print("֦অ \(name)") } } Person(name: "Wei Wang").greet()
ಥɾ૬ ܐᦓಘᶎݻܐᦓᖫᑕ
OOP ࢯह • ۖாၝݎਞق • ཞڔىဳᅩ
protocol Greetable { var name: String { get } func
greet() } struct Person: Greetable { let name: String func greet() { print("֦অ \(name)") } }
protocol Greetable { var name: String { get } func
greet() } struct Cat: Greetable { let name: String func greet() { print("meow~ \(name)") } }
let array: [Greetable] = [ Person(name: "Wei Wang"), Cat(name: "onevcat")]
for obj in array { obj.greet() } // ֦অ Wei Wang // meow~ onevcat
struct Bug: Greetable { let name: String } // Compiler
Error: // 'Bug' does not conform to protocol 'Greetable' // protocol requires function 'greet()'
OOP ࢯह • ✅ ۖாၝݎਞق • ཞڔىဳᅩ
ֵአܐᦓوՁդᎱ protocol P { func myMethod() }
// class ViewController: UIViewController extension ViewController: P { func myMethod()
{ doWork() } } // class AnotherViewController: UITableViewController extension AnotherViewController: P { func myMethod() { doWork() } }
Swi$ 2 - ܐᦓಘ
protocol P { func myMethod() } extension P { func
myMethod() { doWork() } } ԅ P ਧԎጱොဩ׀ἕᦊਫሿ
extension ViewController: P { } extension AnotherViewController: P { }
viewController.myMethod() anotherViewController.myMethod()
ਫሿ๚ࣁܐᦓӾ्กጱٖ protocol P { func myMethod() } extension P {
func myMethod() { doWork() } func anotherMethod() { myMethod() someOtherWork() } } viewController.anotherMethod()
• ܐᦓਧԎ • ׀ਫሿጱفݗ • ᭽ܐᦓጱᔄࣳᵱᥝٌᬰᤈਫሿ • ܐᦓಘ • ԅفݗ׀ἕᦊਫሿ
• ໑ഝفݗ׀᷐क़ਫሿ
OOP ࢯह • ✅ ۖாၝݎਞق • ✅ ཞڔىဳᅩ
ɾᅾ ࣁ෭ଉݎӾֵአܐᦓ
WWDC 15 #408 Protocol-Oriented Programming in Swi3
Model (Networking)
ໜֺ चԭ Protocol ጱᗑᕶ᧗
Demo • चԭܐᦓ • ᔄࣳਞق • ᥴᘠݳ • ݢܔᇿၥᦶ •
ಘ
• Networking: • AFNetworking • Alamofire • (ASIHTTPRequest) ! •
Model Parser • SwiAyJSON • Argo • Himotoki
սضᘍᡤֵአܐᦓ ṛଶܐᦓ۸ํۗԭᥴᘠ҅ၥᦶզ݊ಘ
APIKit1 + Himotoki2 2 h$ps:/ /github.com/ikesyo/Himotoki 1 h$ps:/ /github.com/ishkawa/APIKit
Controller
ໜֺ ړᶭے
ړᶭےጱᗑᕶ᧗ struct Pagination<T> { let items: [T] let hasNext: Bool
} struct ChannelsResquest: Request { typealias Response = Pagination<Channel> let lastId: Int? }
class ChannelsTableViewController: UITableViewController { private var lastId: Int? = nil
private var hasNext = true override func viewDidLoad() { super.viewDidLoad() load() } func load() { if hasNext { client.send(ChannelsResquest(lastId: lastId)) { result in } } } }
class ChannelsTableViewController: UITableViewController { private var lastId: Int? = nil
private var hasNext = true private var data: [Channel] = [] override func viewDidLoad() { super.viewDidLoad() load() } func load() { if hasNext { client.send(ChannelsResquest(lastId: lastId)) { result in self.lastId = result!.items.last?.id self.hasNext = result!.hasNext self.data = result.items self.tableView.reloadData() } } } }
extension ChannelsTableViewController: UITableViewDelegate { override func tableView(tableView: UITableView, willDisplayCell cell:
UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row == data.count - 1 { load() } }
ඳԪᬮဌํᕮ...
ඳԪᬮဌํᕮ... private var isLoading = false func load() { if
isLoading { return } if hasNext { isLoading = true client.send(ChannelsResquest(lastId: lastId)) { result in //... self.isLoading = false } } }
ChannelsTableViewController Pagina&on<Channel>
FriendsTableViewController Pagina&on<Friend>
ොໜӞғ॔ګᔌᩂ
ොໜӞғ॔ګᔌᩂ
ොໜԫғᆿᔄ
BaseTableViewController
class BaseTableViewController: UITableViewController { var lastId: Int? = nil var
hasNext = true var isLoading = false func loadNext() { if isLoading { return } if hasNext { isLoading = true doLoad {result in self.lastId = //... self.hasNext = //... } } } func doLoad(handler: (Any?)->Void) { // ?? } }
class BaseTableViewController: UITableViewController { var lastId: Int? = nil var
hasNext = true var isLoading = false func loadNext() { if isLoading { return } if hasNext { isLoading = true doLoad {result in self.lastId = //... self.hasNext = //... } } } func doLoad(handler: (Any?)->Void) { fatalError("You should implement it in subclass!") } }
class FriendsTableViewController: BaseTableViewController { private var data: [Friend] = []
override func viewDidLoad() { super.viewDidLoad() loadNext() } override func doLoad(handler: (Any?)->Void) { client.send(FriendsRequest(lastId: lastId)) { result in handler(result) // ... self.data = result!.items self.tableView.reloadData() } } }
None
None
WTF?
• FriendsTableViewController → FriendsCollec5onViewController
• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController
• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController ॔ګᔌᩂ?
• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController ॔ګᔌᩂ
ොໜӣғܐᦓ
struct NextPageState<T> { private(set) var hasNext: Bool private(set) var isLoading:
Bool private(set) var lastId: T? init() { hasNext = true isLoading = false lastId = nil } mutating func reset() { hasNext = true isLoading = false lastId = nil } mutating func update(hasNext: Bool, isLoading: Bool, lastId: T?) { self.hasNext = hasNext self.isLoading = isLoading self.lastId = lastId } }
protocol NextPageLoadable: class { associatedtype DataType associatedtype LastIdType var data:
[DataType] { get set } var nextPageState: NextPageState<LastIdType> { get set } func performLoad( successHandler: (_ rows: [DataType], _ hasNext: Bool, _ lastId: LastIdType?) -> (), failHandler: () -> () ) }
protocol NextPageLoadable: class { associatedtype DataType associatedtype LastIdType var data:
[DataType] { get set } var nextPageState: NextPageState<LastIdType> { get set } func performLoad( successHandler: (_ rows: [DataType], _ hasNext: Bool, _ lastId: LastIdType?) -> (), failHandler: () -> () ) } extension NextPageLoadable where Self: UITableViewController { func loadNext() { guard nextPageState.hasNext else { return } if nextPageState.isLoading { return }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { guard
nextPageState.hasNext else { return } if nextPageState.isLoading { return } nextPageState.isLoading = true performLoad(successHandler: { rows, hasNext, lastId in self.data += rows self.nextPageState.update(hasNext: hasNext, isLoading: false, lastId: lastId)
extension NextPageLoadable where Self: UITableViewController { func loadNext() { guard
nextPageState.hasNext else { return } if nextPageState.isLoading { return } nextPageState.isLoading = true performLoad(successHandler: { rows, hasNext, lastId in self.data += rows self.nextPageState.update(hasNext: hasNext, isLoading: false, lastId: lastId) self.tableView.reloadData() }, failHandler: { //.. }) } }
class FriendTableViewController: UITableViewController { var nextPageState = NextPageState<Int>() var data:
[Friend] = [] } extension FriendTableViewController: NextPageLoadable { func performLoad( successHandler: ([String], Bool, Int?) -> (), failHandler: () -> ()) { client.send(FriendsRequest()) { result in if let result = result { successHandler(result.items, result.hasNext, result.items.last.id) } else { failHandler() } } } }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { ...
} }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { ...
} } extension FriendTableViewController: NextPageLoadable { ... } class FriendTableViewController: UITableViewController { //... override func viewDidLoad() { super.viewDidLoad() loadNext() } override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row == data.count - 1 { loadNext() } } }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { ...
} } UICollec(onView ெԍېҘ
extension NextPageLoadable where Self: UITableViewController { func loadNext() { ...
} } UICollec(onView ெԍېҘ ॔ګᔌᩂҘ extension NextPageLoadable where Self: UICollectionViewController { func loadNext() { ... } }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { guard
nextPageState.hasNext else { return } if nextPageState.isLoading { return } nextPageState.isLoading = true performLoad(successHandler: { rows, hasNext, lastId in self.data += rows self.nextPageState.update(hasNext: hasNext, isLoading: false, lastId: lastId) self.tableView.reloadData() }, failHandler: { // Failed when first loading if self.nextPageState.lastId == nil { self.data = [] self.nextPageState.reset() } }) } }
tableView.reloadData() colletionView.reloadData()
tableView.reloadData() colletionView.reloadData() protocol ReloadableType { func reloadData() } extension UITableView:
ReloadableType {} extension UICollectionView: ReloadableType {}
extension NextPageLoadable where Self: UITableViewController { func loadNext() { //...
self.tableView.reloadData() //... } }
extension NextPageLoadable { func loadNext(view: ReloadableType) { //... view.reloadData() //...
} }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { loadNext(reloadView:
tableView) } }
extension NextPageLoadable where Self: UITableViewController { func loadNext() { loadNext(reloadView:
tableView) } } extension NextPageLoadable where Self: UICollectionViewController { func loadNext() { loadNext(reloadView: collectionView) } }
• FriendsTableViewController → FriendsCollec5onViewController
class FriendTableViewController: UITableViewController { var nextPageState = NextPageState<Int>() var data:
[Friend] = [] } extension FriendTableViewController: NextPageLoadable { func performLoad( successHandler: ([String], Bool, Int?) -> (), failHandler: () -> ()) { client.send(FriendsRequest()) { result in if let result = result { successHandler(result.items, result.hasNext, result.items.last.id) } else { failHandler() } } } }
class FriendCollectionViewController: UITableViewController { var nextPageState = NextPageState<Int>() var data:
[Friend] = [] } extension FriendCollectionViewController: NextPageLoadable { func performLoad( successHandler: ([String], Bool, Int?) -> (), failHandler: () -> ()) { client.send(FriendsRequest()) { result in if let result = result { successHandler(result.items, result.hasNext, result.items.last.id) } else { failHandler() } } } }
ViewController ၥᦶ
ֵአܐᦓᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺᖀಥ)
ֵአܐᦓᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺᖀಥ) • ֵአܐᦓ̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ
ֵአܐᦓᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺᖀಥ) • ֵአܐᦓ̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ
• ਖ਼դᎱᨱձړᐶڊ ViewController
ֵአܐᦓᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺᖀಥ) • ֵአܐᦓ̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ
• ਖ਼դᎱᨱձړᐶڊ ViewController • ֵአ᯿ጱොဩਖ਼ܐᦓ᭑Ⴙ᭗አ۸
ݳɾജ ֵአܐᦓଆۗද࠺դᎱᦡᦇ
വគᩒා • Protocol-Oriented Programming in Swi4 - WWDC 15 #408
• Protocols with Associated Types - @alexisgallagher • Protocol Oriented Programming in the Real World - @_maHhewpalmer • PracIcal Protocol-Oriented-Programming - @natashatherobot
ᨀᨀᘰލ FAQ Email:
[email protected]
, GitHub: onevcat