-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
577 lines (482 loc) · 36.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
<!DOCTYPE html>
<html lang="en">
<head>
<title>WinkKit Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset='utf-8'>
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
</head>
<body>
<a title="WinkKit Reference"></a>
<header>
<div class="content-wrapper">
<p><a href="index.html">WinkKit Docs</a> (78% documented)</p>
</div>
</header>
<div class="content-wrapper">
<p id="breadcrumbs">
<a href="index.html">WinkKit Reference</a>
<img id="carat" src="img/carat.png" />
WinkKit Reference
</p>
</div>
<div class="content-wrapper">
<nav class="sidebar">
<ul class="nav-groups">
<li class="nav-group-name">
<a href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Classes/Log.html">Log</a>
</li>
<li class="nav-group-task">
<a href="Classes/OrderedSet.html">OrderedSet</a>
</li>
<li class="nav-group-task">
<a href="Classes/SpinnerTableViewCell.html">SpinnerTableViewCell</a>
</li>
<li class="nav-group-task">
<a href="Classes/VoidPresenter.html">VoidPresenter</a>
</li>
<li class="nav-group-task">
<a href="Classes.html#/s:7WinkKit8VoidViewC">VoidView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKButton.html">WKButton</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKCollectionView.html">WKCollectionView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKCollectionViewCell.html">WKCollectionViewCell</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKCollectionViewController.html">WKCollectionViewController</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKCollectionViewDataSource.html">WKCollectionViewDataSource</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKImageView.html">WKImageView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKLabel.html">WKLabel</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKMediaPickerHelper.html">WKMediaPickerHelper</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKNavigationController.html">WKNavigationController</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKNavigator.html">WKNavigator</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKNetworkObservableViewControllerPresenter.html">WKNetworkObservableViewControllerPresenter</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKNetworkReachabilityHelper.html">WKNetworkReachabilityHelper</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKService.html">WKService</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTableView.html">WKTableView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTableViewCell.html">WKTableViewCell</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTableViewController.html">WKTableViewController</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTableViewDataSource.html">WKTableViewDataSource</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTableViewInfiniteDataSourceDelegate.html">WKTableViewInfiniteDataSourceDelegate</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKTextView.html">WKTextView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKView.html">WKView</a>
</li>
<li class="nav-group-task">
<a href="Classes/WKViewController.html">WKViewController</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Enums.html">Enums</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Enums/UIColorInputError.html">UIColorInputError</a>
</li>
<li class="nav-group-task">
<a href="Enums/WKMediaType.html">WKMediaType</a>
</li>
<li class="nav-group-task">
<a href="Enums/WKPickerResult.html">WKPickerResult</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Extensions/CALayer.html">CALayer</a>
</li>
<li class="nav-group-task">
<a href="Extensions/Date.html">Date</a>
</li>
<li class="nav-group-task">
<a href="Extensions/String.html">String</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UIAlertController.html">UIAlertController</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UICollectionView.html">UICollectionView</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UIColor.html">UIColor</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UIImage.html">UIImage</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UITableView.html">UITableView</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UIView.html">UIView</a>
</li>
<li class="nav-group-task">
<a href="Extensions/UIWindow.html">UIWindow</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Functions.html">Functions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Functions.html#/s:7WinkKit1poiAA10OrderedSetCyxGAE_q_ts8HashableRz7ElementQy_Rszs8SequenceR_r0_lF">+(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:7WinkKit2peoiyAA10OrderedSetCyxGz_q_ts8HashableRz7ElementQy_Rszs8SequenceR_r0_lF">+=(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:7WinkKit1soiAA10OrderedSetCyxGAE_q_ts8HashableRz7ElementQy_Rszs8SequenceR_r0_lF">-(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:7WinkKit2seoiyAA10OrderedSetCyxGz_q_ts8HashableRz7ElementQy_Rszs8SequenceR_r0_lF">-=(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:7WinkKit2eeoiSbAA10OrderedSetCyxG_AEts8HashableRzlF">==(_:_:)</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Protocols/NetworkObservableView.html">NetworkObservableView</a>
</li>
<li class="nav-group-task">
<a href="Protocols.html#/s:7WinkKit15PresentableViewP">PresentableView</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKBaseViewController.html">WKBaseViewController</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKGenericViewControllerPresenter.html">WKGenericViewControllerPresenter</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKInstantiableViewController.html">WKInstantiableViewController</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKMedia.html">WKMedia</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKNetworkObserver.html">WKNetworkObserver</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKPresenter.html">WKPresenter</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKPropertiesInspectable.html">WKPropertiesInspectable</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WKRouter.html">WKRouter</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Structs.html">Structs</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Structs/OrderedSetGenerator.html">OrderedSetGenerator</a>
</li>
<li class="nav-group-task">
<a href="Structs/Queue.html">Queue</a>
</li>
<li class="nav-group-task">
<a href="Structs/WKCustomLayerStyleKey.html">WKCustomLayerStyleKey</a>
</li>
<li class="nav-group-task">
<a href="Structs/WKMediaImage.html">WKMediaImage</a>
</li>
<li class="nav-group-task">
<a href="Structs/WKMediaVideo.html">WKMediaVideo</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Subscripts.html">Subscripts</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Subscripts.html#/s:s10CollectionP7WinkKitE9subscript7ElementQzSg5IndexQz4safe_tci">subscript(safe:)</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Typealiases.html">Typealiases</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Typealiases.html#/s:7WinkKit16WKPickerCallbacka">WKPickerCallback</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section>
<section class="section">
<p align="center">
<img src="readme-res/winkkit_logo.png" width="33%">
</p>
<h1 id='winkkit' class='heading'>WinkKit</h1>
<p><a href="http://cocoapods.org/pods/WinkKit"><img src="https://img.shields.io/cocoapods/v/WinkKit.svg?style=flat" alt="CocoaPods Version"></a>
<a href="http://cocoapods.org/pods/WinkKit"><img src="https://img.shields.io/cocoapods/l/WinkKit.svg?style=flat" alt="License"></a>
<a href="http://cocoapods.org/pods/WinkKit"><img src="https://img.shields.io/badge/platform-iOS-blue.svg" alt="Platforms"></a>
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/swift-4.0-orange.svg?style=flat" alt="Swift Version"></a></p>
<p>An iOS framework that contains a set of classes that follow MVP pattern and solve some common problem written in Swift, used for Wink’s application. Follow this guide to know how to structure a Wink iOS project.</p>
<h2 id='table-of-contents' class='heading'>Table of Contents</h2>
<ol>
<li><a href="#Getting_Started">Getting Started</a></li>
<li><a href="#Understanding_Structure">Understanding Structure</a></li>
<li><a href="#UI_Extension">Using enhanced Views</a></li>
<li><a href="#Using_ViewControllers">Using ViewControllers and Presenters</a></li>
<li><a href="#Using_TabColViews">Using Table Views and Collection Views</a></li>
<li><a href="#Utils_And_More">Utils and more</a></li>
</ol>
<h2 id='getting-started-a-name-getting_started-a' class='heading'>Getting Started <a name="Getting_Started"></a></h2>
<h3 id='prerequisites' class='heading'>Prerequisites</h3>
<p>You need <a href="https://developer.apple.com/xcode/">Xcode 9</a>, Swift 4 and <a href="https://guides.cocoapods.org/using/getting-started.html">CocoaPods</a> installed.</p>
<h3 id='installing' class='heading'>Installing</h3>
<p>Just paste the CocoaPods dependency in your <code>podfile</code>. Due to a cocoapods bug, ensure to paste the <strong>post_install</strong> function too.</p>
<pre class="highlight ruby"><code><span class="c1"># Podfile</span>
<span class="n">use_frameworks!</span>
<span class="n">target</span> <span class="s1">'YOUR_TARGET_NAME'</span> <span class="k">do</span>
<span class="c1"># https://github.com/WINKgroup/WinkKit</span>
<span class="n">pod</span> <span class="s1">'WinkKit'</span>
<span class="k">end</span>
<span class="c1"># This post install is needed because of a Cocoapods bug; it is needed to render WinkKit properties in InterfaceBuilder correctly.</span>
<span class="n">post_install</span> <span class="k">do</span> <span class="o">|</span><span class="n">installer</span><span class="o">|</span>
<span class="n">installer</span><span class="p">.</span><span class="nf">pods_project</span><span class="p">.</span><span class="nf">targets</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">target</span><span class="o">|</span>
<span class="n">target</span><span class="p">.</span><span class="nf">build_configurations</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">config</span><span class="p">.</span><span class="nf">build_settings</span><span class="p">[</span><span class="s1">'CONFIGURATION_BUILD_DIR'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'$PODS_CONFIGURATION_BUILD_DIR'</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p><strong>N.B.</strong>: If you have compilation fails related to <code>AlamofireImage</code> target in generated Pod project, set Swift version to 3.2 for that target.</p>
<h3 id='add-project-file-templates-to-xcode-optional-but-recommended' class='heading'>Add project/file templates to Xcode (Optional but recommended)</h3>
<p>WinkKit has been designed to help creating app with MVP pattern (you’ll understand better later); to follow this pattern, it’s needed to create for each view several files.
WinkKit contains a set of Xcode templates to make file creation faster; download <a href="./Xcode%20Templates/Template%20Files/Wink%20Kit.zip" download target="_blank" download>Template File</a>, extract and copy <q>Wink Kit</q> folder to </p>
<pre class="highlight plaintext"><code>/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates
</code></pre>
<p>Now in Xcode, under <strong>File > New > File</strong> (or CMD+N) you can create view controllers, table view cells and collection view cells that conform to MVP like following.</p>
<p align="center">
<img src="readme-res/template_files.png" width="50%">
</p>
<h2 id='api-documentation' class='heading'>API Documentation</h2>
<h3 id='check-the-classes-reference-a-href-docs-index-html-here-a' class='heading'>Check the classes reference <a href="./docs/index.html">here</a>.</h3>
<h2 id='understanding-structure-a-name-understanding_structure-a' class='heading'>Understanding Structure <a name="Understanding_Structure"></a></h2>
<p>Before talking about classes of framework we’ll take a look on architecture structure. </p>
<p>It is a MVP pattern; look at this <a href="https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52">iOS Architectures overview</a> to understand differences between MVC, MVP, MVVM, VIPER.</p>
<p>A Wink iOS project <strong>should</strong> be structured in the following way, expecially if the project will grow a lot:</p>
<p><img src="./readme-res/arch_diagram.jpg" alt="Arch diagram"></p>
<p>This kind of architecture is try to follow the <strong>Responsability Distribution</strong> concept: each layer exists without other ones and every component has different responsability; this improves the maintanance and the testability. The whole Xcode proj structure that maps this architecture is something like this:</p>
<p><img src="readme-res/xcode_structure.png" width=50% /></p>
<p><br></p>
<h3 id='presentation' class='heading'>Presentation</h3>
<p>It’s the layer that contains all iOS Framework dedicated classes, like <code>UIKit</code> framework. We could say that this layer cannot exists without an iPhone/iPad because <code>UIKit</code> can run only there.</p>
<p><img src="readme-res/presentation_layer.png" width=50% /></p>
<ul>
<li><strong>AppDelegate</strong>: It’s the well known AppDelegate class, nothing special;</li>
<li><strong>Use Cases</strong>: A group that contains all use cases. It’s important to understand that a <em>Use Case</em> is what user do in one or more app screen, for example the Login.
<ul>
<li><strong>Login</strong>: En example of a Use Case. It will contain all related ViewControllers, Presenter (if a use case contains more than one), DataSources etc.
<ul>
<li><strong>LoginPresenter</strong>: A simple presenter; LoginPresenter keep the state of LoginViewController; a presenter is the class that contains logic, the ViewController does <strong>not</strong> contain logic. <strong>Presenter doesn’t contains UIKit classes!</strong>, this is needed to keep presenters easy testable.</li>
<li><strong>LoginViewController</strong>: In classic MVC pattern, (Massive View Controller in iOS world 😫) all logic was here, mixed with the view handling; in this framework a ViewController <strong>owns</strong> a presenter and delegates it for the logic. The view controller doesn’t have a method <code>func performLogin(email: String, password: String)</code> for example; instead, the presenter does. The view controller will only receive user input and tell the presenter that something happened. The presenter will do work and tell the view controller that the view should change.</li>
</ul></li>
</ul></li>
<li><strong>Core</strong>: A group that contains base classes re-usable all around project. It’s a good practice to define this classes to avoid code duplication that could increase the maintanance difficulty.\</li>
<li><strong>Resources</strong>: All resources go here, included .xcassets, custom fonts…</li>
</ul>
<p><br></p>
<h3 id='data' class='heading'>Data</h3>
<p>It’s the layer that handles all data stuff, such as http calls, cache uploading/downloading to/from a backend. No <code>UIKit</code> classes in this layer!</p>
<p><img src="readme-res/data_layer.png" width=50% /></p>
<ul>
<li><strong>Cache</strong>: A group that contains classes like SessionManager and all other stuff that saves data locally.</li>
<li><strong>Networking</strong>: The group that contains the Http Client, which must be implemented with <strong>Alamofire</strong>. WinkKit provides <a href="https://github.com/Alamofire/Alamofire">Alamofire</a> and <a href="https://github.com/Alamofire/AlamofireImage">Alamofire Image</a> in the framework itself, so you don’t need to add anything in the Podfile.
<ul>
<li><strong>ResponseSerialization</strong>: Contains the <code>DataResponse</code> extension of Alamofire: it provides a common response for http calls that return an object instead of a json; json parsing is done in this extension (see source file for detail). Notice that this extension uses <a href="https://github.com/thoughtbot/Argo">Argo</a> for json parsing.</li>
<li><strong>Resource</strong>: an enum that maps the response of https calls.</li>
<li><strong>Error</strong>: the class/struct that maps http errors (both client and server)</li>
<li><strong>Routers</strong>: Routers are responsible to know api’s endpoints and to create a <code>urlRequest</code> that are used by <strong>Services</strong> to perform http calls.</li>
<li><strong>Services</strong>: Services perform http calls, using the request created by routers.</li>
</ul></li>
</ul>
<p><br></p>
<h1 id='presentation' class='heading'>Presentation</h1>
<h2 id='using-enhanced-views-a-name-ui_extension-a' class='heading'>Using enhanced Views <a name="UI_Extension"></a></h2>
<p>WinkKit provides common view classes that have more <code>@IBDesignable</code> in InterfaceBuilder.</p>
<ul>
<li>WKView</li>
<li>WKImageView</li>
<li>WKButton</li>
<li>WKLabel</li>
<li>WKTextView</li>
</ul>
<p>Every class extends the <code>UIKit</code> one; for example <code>WKView</code> extends <code>UIView</code>. To use these classes in InterfaceBuilder, drag the object from the Object library and make it extends the desired WinkKit view.
For example to use a <code>WKButton</code>, drag a Button from Object library, then go to Identity Inspector and set the custom class:</p>
<p><img src="readme-res/button_identity_inspector.png" width="40%"></p>
<p><strong>Make sure to leave WinkKit as module</strong></p>
<p>Then you can customize the button from Attributes inspector:</p>
<p><img src="readme-res/button_attributes_inspector.png" width="40%"></p>
<h2 id='using-viewcontrollers-and-presenters-a-name-using_viewcontrollers-a' class='heading'>Using ViewControllers and Presenters <a name="Using_ViewControllers"></a></h2>
<p>In a WinkKit app every view controller should extends the <code>WKViewController<P></code> (or <code>WKTableViewController<P></code> or <code>WKCollectionViewContrller<P></code>, they have all same behaviours).</p>
<p>A <code>WKViewController</code> wants a subclass of <code>WKGenericViewControllerPresenter</code> (which is a protocol that extends the base presenter protocol <code>WKPresenter</code>) because the view controller life-cycle is bound to this kind of presenter. A typical implementation of home page is</p>
<pre class="highlight swift"><code><span class="c1">// HomeViewController.swift</span>
<span class="kd">class</span> <span class="kt">HomeViewController</span><span class="p">:</span> <span class="kt">WKViewController</span><span class="o"><</span><span class="kt">HomePresenter</span><span class="o">></span> <span class="p">{</span>
<span class="c1">// do only UI stuff here</span>
<span class="p">}</span>
<span class="c1">// Since the view controller is handled by HomePresenter, it must be conform to LoginView.</span>
<span class="kd">extension</span> <span class="kt">HomeViewController</span><span class="p">:</span> <span class="kt">LoginView</span> <span class="p">{</span>
<span class="c1">// implements all HomeView methods/properties</span>
<span class="p">}</span>
<span class="c1">// HomePresenter.swift</span>
<span class="c1">// Define what the view can do</span>
<span class="kd">protocol</span> <span class="kt">LoginView</span><span class="p">:</span> <span class="kt">PresentableView</span> <span class="p">{</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="kt">HomePresenter</span><span class="p">:</span> <span class="kt">WKGenericViewControllerPresenter</span> <span class="p">{</span>
<span class="kd">typealias</span> <span class="kt">View</span> <span class="o">=</span> <span class="kt">LoginView</span> <span class="c1">// need to tell the protocol which is the view handled</span>
<span class="k">weak</span> <span class="k">var</span> <span class="nv">view</span><span class="p">:</span> <span class="kt">LoginView</span><span class="p">?</span> <span class="c1">// keep view weak to avoid retain-cycle since view controller holds a reference to this presenter</span>
<span class="kd">required</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{}</span> <span class="c1">// framework wants empty init</span>
<span class="c1">// do all logic here, such as use a Service to fetch data and tell the view to update</span>
<span class="p">}</span>
</code></pre>
<p><strong>Notice that you don’t need to call any method to bind the view controller and the presenter, everything is automatically done by the framework!</strong> 🎉🎉🎉</p>
<p>HomePresenter and HomeViewController are two different files. You can use the file template to create quickly this structure 😉.</p>
<h2 id='using-table-views-and-collection-views-a-name-using_tabcolviews-a' class='heading'>Using Table Views and Collection Views <a name="Using_TabColViews"></a></h2>
<p>WinkKit provides both <code>WKTableView</code>, <code>WKCollectionView</code> and <code>WKTableViewCell</code>, <code>WKCollectionViewCell</code>.
Let’s talk about <code>WKTableView</code> and <code>WKTableViewCell</code> (collection view has same logic).</p>
<p><strong>N.B.</strong>: To have a better structure, all cell must have a xib: do <strong>not</strong> create cell in the storyboard directly.</p>
<p>The <code>WKTableView</code> provides two methods to register and dequeue a <code>WKTableViewCell</code> quickly by doing:</p>
<pre class="highlight swift"><code><span class="n">tableView</span><span class="o">.</span><span class="nf">register</span><span class="p">(</span><span class="nv">cell</span><span class="p">:</span> <span class="kt">ItemTableViewCell</span><span class="o">.</span><span class="k">self</span><span class="p">)</span> <span class="c1">// register the cell with a xib that has same name of the class</span>
<span class="n">tableView</span><span class="o">.</span><span class="nf">dequeueReusableCell</span><span class="p">(</span><span class="nv">ofType</span><span class="p">:</span> <span class="kt">ItemTableViewCell</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">for</span><span class="p">:</span> <span class="n">indexPath</span><span class="p">)</span> <span class="c1">// dequeue a cell, already casted</span>
</code></pre>
<p>Cell acts like view controller: they have a presenter (in this case the plain <code>WKPresenter</code>) and they must conform to the view that the presenter handles. For this reason creating a cell is like creating a view controller:</p>
<pre class="highlight swift"><code><span class="c1">// ItemTableViewCell.swift</span>
<span class="kd">class</span> <span class="kt">ItemTableViewCell</span><span class="p">:</span> <span class="kt">WKTableViewCell</span><span class="o"><</span><span class="kt">ItemPresenter</span><span class="o">></span> <span class="p">{</span>
<span class="c1">// do only UI stuff here</span>
<span class="p">}</span>
<span class="kd">extension</span> <span class="kt">ItemTableViewCell</span><span class="p">:</span> <span class="kt">ItemView</span> <span class="p">{</span>
<span class="c1">// implements all ItemView methods/properties </span>
<span class="p">}</span>
<span class="c1">// ItemPresenter.swift</span>
<span class="c1">/// The protocol that the cell handled by presenter must conforms to.</span>
<span class="kd">protocol</span> <span class="kt">ItemView</span><span class="p">:</span> <span class="kt">PresentableView</span> <span class="p">{</span>
<span class="p">}</span>
<span class="c1">/// The presenter that will handle all logic of the view.</span>
<span class="kd">class</span> <span class="kt">ItemPresenter</span><span class="p">:</span> <span class="kt">WKPresenter</span> <span class="p">{</span>
<span class="kd">typealias</span> <span class="kt">View</span> <span class="o">=</span> <span class="kt">ItemView</span>
<span class="c1">// The view associated to this presenter. Keep weak to avoid retain-cycle</span>
<span class="k">weak</span> <span class="k">var</span> <span class="nv">view</span><span class="p">:</span> <span class="kt">ItemView</span><span class="p">?</span>
<span class="c1">// the item that will be showed in this cell</span>
<span class="kd">private</span> <span class="k">var</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">Item</span><span class="o">!</span>
<span class="nf">init</span><span class="p">(</span><span class="n">with</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">Item</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">item</span> <span class="o">=</span> <span class="n">item</span>
<span class="p">}</span>
<span class="c1">// do all logic here</span>
<span class="p">}</span>
</code></pre>
<p>You can use template to quickly create all of those class/protocols 😁.</p>
<p>Unlike view controllers, a cell must be configured after dequeued in the data source by doing something like:</p>
<pre class="highlight swift"><code><span class="kd">func</span> <span class="nf">tableView</span><span class="p">(</span><span class="n">_</span> <span class="nv">tableView</span><span class="p">:</span> <span class="kt">UITableView</span><span class="p">,</span> <span class="n">cellForRowAt</span> <span class="nv">indexPath</span><span class="p">:</span> <span class="kt">IndexPath</span><span class="p">)</span> <span class="o">-></span> <span class="kt">UITableViewCell</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">cell</span> <span class="o">=</span> <span class="n">tableView</span><span class="o">.</span><span class="nf">dequeueReusableCell</span><span class="p">(</span><span class="nv">ofType</span><span class="p">:</span> <span class="kt">ItemTableViewCell</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">for</span><span class="p">:</span> <span class="n">indexPath</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">presenter</span> <span class="o">=</span> <span class="kt">ItemPresenter</span><span class="p">()</span> <span class="c1">// create a presenter</span>
<span class="n">cell</span><span class="o">.</span><span class="nf">configure</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">presenter</span><span class="p">)</span> <span class="c1">// configure the cell with the presenter</span>
<span class="k">return</span> <span class="n">cell</span>
<span class="p">}</span>
</code></pre>
<h3 id='collection-view-and-table-view-data-source' class='heading'>Collection View and Table View data source</h3>
<p>As a best practice, it’s better to decouple data sources from view controller. Avoid making a view controller as a data source to have all stuff better separated and re-usable. To communicate from data source to view controller, is it possible to use closures or delegation pattern. A typical implementation of a simple table view data source could be like:</p>
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">ItemDataSource</span><span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt">UITableViewDataSource</span> <span class="p">{</span>
<span class="kd">private</span> <span class="k">var</span> <span class="nv">items</span> <span class="o">=</span> <span class="p">[</span><span class="kt">Any</span><span class="p">]()</span>
<span class="nf">init</span><span class="p">(</span><span class="nv">tableView</span><span class="p">:</span> <span class="kt">WKTableView</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// register cell here so when you need this data source you don't have to repeat this line of code</span>
<span class="n">tableView</span><span class="o">.</span><span class="nf">register</span><span class="p">(</span><span class="nv">cell</span><span class="p">:</span> <span class="kt">ItemTableViewCell</span><span class="o">.</span><span class="k">self</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">tableView</span><span class="p">(</span><span class="n">_</span> <span class="nv">tableView</span><span class="p">:</span> <span class="kt">UITableView</span><span class="p">,</span> <span class="n">numberOfRowsInSection</span> <span class="nv">section</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Int</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">items</span><span class="o">.</span><span class="n">count</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">tableView</span><span class="p">(</span><span class="n">_</span> <span class="nv">tableView</span><span class="p">:</span> <span class="kt">UITableView</span><span class="p">,</span> <span class="n">cellForRowAt</span> <span class="nv">indexPath</span><span class="p">:</span> <span class="kt">IndexPath</span><span class="p">)</span> <span class="o">-></span> <span class="kt">UITableViewCell</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">cell</span> <span class="o">=</span> <span class="n">tableView</span><span class="o">.</span><span class="nf">dequeueReusableCell</span><span class="p">(</span><span class="nv">ofType</span><span class="p">:</span> <span class="kt">ItemTableViewCell</span><span class="o">.</span><span class="k">self</span><span class="p">,</span> <span class="nv">for</span><span class="p">:</span> <span class="n">indexPath</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">presenter</span> <span class="o">=</span> <span class="kt">ItemPresenter</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">items</span><span class="p">[</span><span class="n">indexPath</span><span class="o">.</span><span class="n">row</span><span class="p">])</span>
<span class="n">cell</span><span class="o">.</span><span class="nf">configure</span><span class="p">(</span><span class="nv">with</span><span class="p">:</span> <span class="n">presenter</span><span class="p">)</span>
<span class="k">return</span> <span class="n">cell</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>Then in your view controller use the data source as instance variable.</p>
<p><strong>Tips</strong>: <code>WinkKit</code> provides few ready data source classes that have common methods, like inserting/deleting/reloading items or handle infinite scroll. Check <code>WKTableViewDataSource</code>, <code>WKCollectionViewDataSource</code> and <code>WKTableViewInfiniteDataSourceDelegate</code>. </p>
<h2 id='utils-and-more-a-name-utils_and_more-a' class='heading'>Utils and more <a name="Utils_And_More"></a></h2>
<p>There are other classes and extensions that can be used to achieve some behaviour:</p>
<ul>
<li>Classes:
<ul>
<li><code>Logger</code>: contains methods to log info and to avoid print debug info in release mode;</li>
<li><code>OrderedSet</code>: it’s like a <code>Set</code> but elements are ordered;</li>
<li><code>Queue</code>: a simple queue class</li>
</ul></li>
<li>Extensions:
<ul>
<li><code>UIAlertController</code>: contains method to show quickly an alert</li>
<li><code>Date</code>: contains an <code>init</code> to create a date from a string and a format and some methods to get day, hour of month</li>
<li><code>Collection</code>: constains a subscript to access values even if the index is wrong (it returns an optional)</li>
<li><code>CALayer</code>: contains method to add border to a layer</li>
<li><code>UIColor</code>: allow color creation with a hex string</li>
<li><code>UIWindow</code>: contains method to get the current top most view controller.</li>
</ul></li>
</ul>
<h2 id='authors' class='heading'>Authors</h2>
<p><strong>Rico Crescenzio</strong> - <a href="https://www.linkedin.com/in/quirico-crescenzio-810263b9/">Linkedin</a></p>
<h2 id='license' class='heading'>License</h2>
<p>This project is licensed under the MIT License - see the <a href="LICENSE">LICENSE</a> file for details</p>
</section>
</section>
<section id="footer">
<p>© 2018 <a class="link" href="https://github.com/WINKgroup/WinkKit" target="_blank" rel="external">Rico Crescenzio</a>. All rights reserved. (Last updated: 2018-04-06)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.8.1</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</article>
</div>
</body>
</div>
</html>