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.9k
面向协议编程与 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.2k
GMTC 2019 - 在分歧中发展,2019 我们能用 Swift 做什么
onevcat
0
1.1k
从 Swift 到机器学习
onevcat
2
1k
iOS Dev - The Dark Side
onevcat
0
150
Swift 3 - From Expert to Beginner
onevcat
2
220
如何打造一个让人愉快的框架
onevcat
4
22k
JSPatch Introduction
onevcat
0
200
Objective-C Runtime Swizzle
onevcat
0
210
Unity Memory
onevcat
0
150
Other Decks in Technology
See All in Technology
日本のソブリンAIを支えるエヌビディアの生成AIエコシステム
acceleratedmu3n
0
110
AIの個性を理解し、指揮する
shoota
3
610
JAWS UG AI/ML #32 Amazon BedrockモデルのライフサイクルとEOL対応/How Amazon Bedrock Model Lifecycle Works
quiver
1
610
触れるけど壊れないWordPressの作り方
masakawai
0
620
Oracle Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
0
420
DSPy入門
tomehirata
6
850
ゼロコード計装導入後のカスタム計装でさらに可観測性を高めよう
sansantech
PRO
1
640
マルチエージェントのチームビルディング_2025-10-25
shinoyamada
0
240
InsightX 会社説明資料/ Company deck
insightx
0
180
DMMの検索システムをSolrからElasticCloudに移行した話
hmaa_ryo
0
330
今のコンピュータ、AI にも Web にも 向いていないので 作り直そう!!
piacerex
0
220
AI時代の発信活動 ~技術者として認知してもらうための発信法~ / 20251028 Masaki Okuda
shift_evolve
PRO
1
130
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1032
470k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
940
Rails Girls Zürich Keynote
gr2m
95
14k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
140
34k
Thoughts on Productivity
jonyablonski
72
4.9k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1k
How STYLIGHT went responsive
nonsquared
100
5.9k
Six Lessons from altMBA
skipperchong
29
4k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
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