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.8k
面向协议编程与 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
5.1k
GMTC 2019 - 在分歧中发展,2019 我们能用 Swift 做什么
onevcat
0
1k
从 Swift 到机器学习
onevcat
2
1k
iOS Dev - The Dark Side
onevcat
0
140
Swift 3 - From Expert to Beginner
onevcat
2
220
如何打造一个让人愉快的框架
onevcat
4
22k
JSPatch Introduction
onevcat
0
200
Objective-C Runtime Swizzle
onevcat
0
200
Unity Memory
onevcat
0
150
Other Decks in Technology
See All in Technology
組織内、組織間の資産保護に必要なアイデンティティ基盤と関連技術の最新動向
fujie
0
460
全部AI、全員Cursor、ドキュメント駆動開発 〜DevinやGeminiも添えて〜
rinchsan
11
5.5k
An introduction to Claude Code SDK
choplin
3
3k
機械学習を「社会実装」するということ 2025年夏版 / Social Implementation of Machine Learning July 2025 Version
moepy_stats
1
120
Digitization部 紹介資料
sansan33
PRO
1
4.6k
今だから言えるセキュリティLT_Wordpress5.7.2未満を一斉アップデートせよ
cuebic9bic
2
180
デザインレビューをAIにしてもらいたい!
tomuro
2
120
Talk to Someone At Delta Airlines™️ USA Contact Numbers
travelcarecenter
0
160
研究開発部メンバーの働き⽅ / Sansan R&D Profile
sansan33
PRO
3
18k
Bliki (ja), and the Cathedral, and the Bazaar
koic
6
810
Microsoft Fabric ガバナンス設計の一歩目を考える
ryomaru0825
1
160
20150719_Amazon Nova Canvas Virtual try-onアプリ 作成裏話
riz3f7
0
110
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
The World Runs on Bad Software
bkeepers
PRO
70
11k
Fireside Chat
paigeccino
37
3.5k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
A Tale of Four Properties
chriscoyier
160
23k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
840
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
Designing for Performance
lara
610
69k
Writing Fast Ruby
sferik
628
62k
Music & Morning Musume
bryan
46
6.7k
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