Slide 1

Slide 1 text

ᶎݻܐᦓᖫᑕӨ Cocoa ጱᮁᭊ MDCC 16 ሴ૛ - 2016 ଙ 9 ์ 24 ෭

Slide 2

Slide 2 text

Ԇ᷌ • ᩸ɾॳᦩ • ಥɾ૬஌ • ᫨ɾᅾ௡ • ݳɾജ൐

Slide 3

Slide 3 text

Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬஌ • ᫨ɾᅾ௡ • ݳɾജ൐

Slide 4

Slide 4 text

Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬஌ - ܐᦓಘ઀޾ᶎݻܐᦓᖫᑕ • ᫨ɾᅾ௡ • ݳɾജ൐

Slide 5

Slide 5 text

Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬஌ - ܐᦓಘ઀޾ᶎݻܐᦓᖫᑕ • ᫨ɾᅾ௡ - ࣁ෭ଉ୏ݎӾֵአܐᦓ • ݳɾജ൐

Slide 6

Slide 6 text

Ԇ᷌ • ᩸ɾॳᦩ - Ջԍฎ Swi' ܐᦓ • ಥɾ૬஌ - ܐᦓಘ઀޾ᶎݻܐᦓᖫᑕ • ᫨ɾᅾ௡ - ࣁ෭ଉ୏ݎӾֵአܐᦓ • Model (Networking) • ViewController • ݳɾജ൐

Slide 7

Slide 7 text

᩸ɾॳᦩ Ջԍฎ Swi% ܐᦓ Protocol

Slide 8

Slide 8 text

protocol Greetable { var name: String { get } func greet() }

Slide 9

Slide 9 text

ᶎݻ੒᨝ Object-oriented

Slide 10

Slide 10 text

ᶎݻ੒᨝ 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"

Slide 11

Slide 11 text

ViewController → UIViewController class ViewCotroller: UIViewController { // ᖀಥ // view, isFirstResponder()... // ෛے func myMethod() { } }

Slide 12

Slide 12 text

AnotherViewController → UITableViewController → UIViewController class AnotherViewController: UITableViewController { // ᖀಥ // tableView, isFirstResponder()... // ෛے func myMethod() { } }

Slide 13

Slide 13 text

ࢯहԏӞ Cross-Cu'ng Concerns ཞڔىဳᅩ

Slide 14

Slide 14 text

ᥴ٬ොໜ • Copy & Paste • ୚ف BaseViewController • ׁᩢဳف • ग़ᖀಥ

Slide 15

Slide 15 text

Objec&ve-C Message Sending

Slide 16

Slide 16 text

ViewController *v1 = ... [v1 myMethod]; AnotherViewController *v2 = ... [v2 myMethod];

Slide 17

Slide 17 text

NSArray *array = @[v1, v2]; for (id obj in array) { [obj myMethod]; }

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

ࢯहԏԫ Dynamic Dispatch Safety ۖாၝݎਞق௔

Slide 20

Slide 20 text

OOP ࢯह • ۖாၝݎਞق௔ • ཞڔىဳᅩ

Slide 21

Slide 21 text

ܐᦓ Protocol

Slide 22

Slide 22 text

Java, C# Interface

Slide 23

Slide 23 text

Swift protocol

Slide 24

Slide 24 text

Swi$ protocol protocol Greetable { var name: String { get } func greet() }

Slide 25

Slide 25 text

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()

Slide 26

Slide 26 text

ಥɾ૬஌ ܐᦓಘ઀޾ᶎݻܐᦓᖫᑕ

Slide 27

Slide 27 text

OOP ࢯह • ۖாၝݎਞق௔ • ཞڔىဳᅩ

Slide 28

Slide 28 text

protocol Greetable { var name: String { get } func greet() } struct Person: Greetable { let name: String func greet() { print("֦অ \(name)") } }

Slide 29

Slide 29 text

protocol Greetable { var name: String { get } func greet() } struct Cat: Greetable { let name: String func greet() { print("meow~ \(name)") } }

Slide 30

Slide 30 text

let array: [Greetable] = [ Person(name: "Wei Wang"), Cat(name: "onevcat")] for obj in array { obj.greet() } // ֦অ Wei Wang // meow~ onevcat

Slide 31

Slide 31 text

struct Bug: Greetable { let name: String } // Compiler Error: // 'Bug' does not conform to protocol 'Greetable' // protocol requires function 'greet()'

Slide 32

Slide 32 text

OOP ࢯह • ✅ ۖாၝݎਞق௔ • ཞڔىဳᅩ

Slide 33

Slide 33 text

ֵአܐᦓوՁդᎱ protocol P { func myMethod() }

Slide 34

Slide 34 text

// class ViewController: UIViewController extension ViewController: P { func myMethod() { doWork() } } // class AnotherViewController: UITableViewController extension AnotherViewController: P { func myMethod() { doWork() } }

Slide 35

Slide 35 text

Swi$ 2 - ܐᦓಘ઀

Slide 36

Slide 36 text

protocol P { func myMethod() } extension P { func myMethod() { doWork() } } ԅ P ਧԎጱොဩ൉׀ἕᦊਫሿ

Slide 37

Slide 37 text

extension ViewController: P { } extension AnotherViewController: P { } viewController.myMethod() anotherViewController.myMethod()

Slide 38

Slide 38 text

ਫሿ๚ࣁܐᦓӾ्กጱٖ਻ protocol P { func myMethod() } extension P { func myMethod() { doWork() } func anotherMethod() { myMethod() someOtherWork() } } viewController.anotherMethod()

Slide 39

Slide 39 text

• ܐᦓਧԎ • ൉׀ਫሿጱفݗ • ᭽஗ܐᦓጱᔄࣳᵱᥝ੒ٌᬰᤈਫሿ • ܐᦓಘ઀ • ԅفݗ൉׀ἕᦊਫሿ • ໑ഝفݗ൉׀᷐क़ਫሿ

Slide 40

Slide 40 text

OOP ࢯह • ✅ ۖாၝݎਞق௔ • ✅ ཞڔىဳᅩ

Slide 41

Slide 41 text

᫨ɾᅾ௡ ࣁ෭ଉ୏ݎӾֵአܐᦓ

Slide 42

Slide 42 text

WWDC 15 #408 Protocol-Oriented Programming in Swi3

Slide 43

Slide 43 text

Model (Networking)

Slide 44

Slide 44 text

ໜֺ चԭ Protocol ጱᗑᕶ᧗࿢

Slide 45

Slide 45 text

Demo • चԭܐᦓ • ᔄࣳਞق • ᥴᘠݳ • ݢܔᇿၥᦶ • ಘ઀௔

Slide 46

Slide 46 text

• Networking: • AFNetworking • Alamofire • (ASIHTTPRequest) ! • Model Parser • SwiAyJSON • Argo • Himotoki

Slide 47

Slide 47 text

սضᘍᡤֵአܐᦓ ṛଶܐᦓ۸ํۗԭᥴᘠ҅ၥᦶզ݊ಘ઀

Slide 48

Slide 48 text

APIKit1 + Himotoki2 2 h$ps:/ /github.com/ikesyo/Himotoki 1 h$ps:/ /github.com/ishkawa/APIKit

Slide 49

Slide 49 text

Controller

Slide 50

Slide 50 text

ໜֺ ړᶭے᫹

Slide 51

Slide 51 text

ړᶭے᫹ጱᗑᕶ᧗࿢ struct Pagination { let items: [T] let hasNext: Bool } struct ChannelsResquest: Request { typealias Response = Pagination let lastId: Int? }

Slide 52

Slide 52 text

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 } } } }

Slide 53

Slide 53 text

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() } } } }

Slide 54

Slide 54 text

extension ChannelsTableViewController: UITableViewDelegate { override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row == data.count - 1 { load() } }

Slide 55

Slide 55 text

ඳԪᬮဌํᕮ๳...

Slide 56

Slide 56 text

ඳԪᬮဌํᕮ๳... private var isLoading = false func load() { if isLoading { return } if hasNext { isLoading = true client.send(ChannelsResquest(lastId: lastId)) { result in //... self.isLoading = false } } }

Slide 57

Slide 57 text

ChannelsTableViewController Pagina&on

Slide 58

Slide 58 text

FriendsTableViewController Pagina&on

Slide 59

Slide 59 text

ොໜӞғ॔ګᔌᩂ

Slide 60

Slide 60 text

ොໜӞғ॔ګᔌᩂ

Slide 61

Slide 61 text

ොໜԫғᆿᔄ

Slide 62

Slide 62 text

BaseTableViewController

Slide 63

Slide 63 text

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) { // ?? } }

Slide 64

Slide 64 text

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!") } }

Slide 65

Slide 65 text

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() } } }

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

WTF?

Slide 69

Slide 69 text

• FriendsTableViewController → FriendsCollec5onViewController

Slide 70

Slide 70 text

• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController

Slide 71

Slide 71 text

• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController ॔ګᔌᩂ?

Slide 72

Slide 72 text

• FriendsTableViewController → FriendsCollec5onViewController • BaseTableViewController → BaseCollec5onViewController ॔ګᔌᩂ

Slide 73

Slide 73 text

ොໜӣғܐᦓ

Slide 74

Slide 74 text

struct NextPageState { 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 } }

Slide 75

Slide 75 text

protocol NextPageLoadable: class { associatedtype DataType associatedtype LastIdType var data: [DataType] { get set } var nextPageState: NextPageState { get set } func performLoad( successHandler: (_ rows: [DataType], _ hasNext: Bool, _ lastId: LastIdType?) -> (), failHandler: () -> () ) }

Slide 76

Slide 76 text

protocol NextPageLoadable: class { associatedtype DataType associatedtype LastIdType var data: [DataType] { get set } var nextPageState: NextPageState { 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 }

Slide 77

Slide 77 text

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)

Slide 78

Slide 78 text

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: { //.. }) } }

Slide 79

Slide 79 text

class FriendTableViewController: UITableViewController { var nextPageState = NextPageState() 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() } } } }

Slide 80

Slide 80 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { ... } }

Slide 81

Slide 81 text

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() } } }

Slide 82

Slide 82 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { ... } } UICollec(onView ெԍېҘ

Slide 83

Slide 83 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { ... } } UICollec(onView ெԍېҘ ॔ګᔌᩂҘ extension NextPageLoadable where Self: UICollectionViewController { func loadNext() { ... } }

Slide 84

Slide 84 text

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() } }) } }

Slide 85

Slide 85 text

tableView.reloadData() colletionView.reloadData()

Slide 86

Slide 86 text

tableView.reloadData() colletionView.reloadData() protocol ReloadableType { func reloadData() } extension UITableView: ReloadableType {} extension UICollectionView: ReloadableType {}

Slide 87

Slide 87 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { //... self.tableView.reloadData() //... } }

Slide 88

Slide 88 text

extension NextPageLoadable { func loadNext(view: ReloadableType) { //... view.reloadData() //... } }

Slide 89

Slide 89 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { loadNext(reloadView: tableView) } }

Slide 90

Slide 90 text

extension NextPageLoadable where Self: UITableViewController { func loadNext() { loadNext(reloadView: tableView) } } extension NextPageLoadable where Self: UICollectionViewController { func loadNext() { loadNext(reloadView: collectionView) } }

Slide 91

Slide 91 text

• FriendsTableViewController → FriendsCollec5onViewController

Slide 92

Slide 92 text

class FriendTableViewController: UITableViewController { var nextPageState = NextPageState() 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() } } } }

Slide 93

Slide 93 text

class FriendCollectionViewController: UITableViewController { var nextPageState = NextPageState() 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() } } } }

Slide 94

Slide 94 text

ViewController ၥᦶ

Slide 95

Slide 95 text

ֵአܐᦓ๶ᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺ੝ᖀಥ)

Slide 96

Slide 96 text

ֵአܐᦓ๶ᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺ੝ᖀಥ) • ֵአܐᦓ๶̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ

Slide 97

Slide 97 text

ֵአܐᦓ๶ᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺ੝ᖀಥ) • ֵአܐᦓ๶̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ • ਖ਼դᎱ޾ᨱձړᐶڊ ViewController

Slide 98

Slide 98 text

ֵአܐᦓ๶ᕟᕢ ViewController • כ೮ᓌܔጱ ViewController ᖀಥ (ٺ੝ᖀಥ) • ֵአܐᦓ๶̿೪ᤰ̀ViewController ಅᵱᥝጱۑᚆ • ਖ਼դᎱ޾ᨱձړᐶڊ ViewController • ֵአ᯿຅ጱොဩਖ਼ܐᦓ᭑Ⴙ᭗አ۸

Slide 99

Slide 99 text

ݳɾജ൐ ֵአܐᦓଆۗද࠺դᎱᦡᦇ

Slide 100

Slide 100 text

വគᩒා • 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

Slide 101

Slide 101 text

ᨀᨀᘰލ FAQ Email: onev@onevcat.com, GitHub: onevcat