Slide 1

Slide 1 text

WELCOME TO REDBOOTH (there are ! and snacks, find them!) TWEET ABOUT THE TALK WITH THE #VIPERTALK HASHTAG

Slide 2

Slide 2 text

REDBOOTH.COM Try it now!

Slide 3

Slide 3 text

2008 TEAMBOX ‑ 2014 REDBOOTH

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

4

Slide 6

Slide 6 text

20

Slide 7

Slide 7 text

35

Slide 8

Slide 8 text

13

Slide 9

Slide 9 text

HOW IS LIFE AT REDBOOTH?

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

REDBOOTH MOBILE TEAM

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

VIPER LOOKING FOR THE PERFECT ARCHITECTURE ! @PEPIBUMUR / @SERGIGRACIA / @SAKY

Slide 22

Slide 22 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 23

Slide 23 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 24

Slide 24 text

DOCUMENTATION, BOOKS, EXAMPLES, TUTORIALS objc.io, RayWenderlich, iOS Dev Weekly, NSHipster

Slide 25

Slide 25 text

PATTERNS PROTOCOLS, DELEGATES, DATA SOURCES KVO

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Remember THEY ARE EXAMPLES

Slide 28

Slide 28 text

VIEWCONTROLLER

Slide 29

Slide 29 text

A VIEW CONTROLLER COORDINATES ITS EFFORTS WITH MODEL OBJECTS AND OTHER CONTROLLER OBJECTS—INCLUDING OTHER VIEW CONTROLLERS — Apple

Slide 30

Slide 30 text

▸ ViewControllerDelegator @interface TBThreadDetailViewController : RBViewController !

Slide 31

Slide 31 text

▸ ViewControllerDelegator @interface TBThreadDetailViewController : RBViewController ! ▸ Multi Responsibility [self presentViewController:previewController animated:YES completion:nil]; //Navigation [Task downloadNewObjectWithID:self.threadIdentifier.remoteIdentifier withSuccess:^{}]; // Networking NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:[Comment entityName]]; // Data persistence [self.view setBackgroundColor:ss_Color_White]; // Formatting !

Slide 32

Slide 32 text

▸ Monster files size > 1500 lines !

Slide 33

Slide 33 text

▸ Monster files size > 1500 lines ! ▸ Impossible to test "

Slide 34

Slide 34 text

▸ Monster files size > 1500 lines ! ▸ Impossible to test " ▸ Components too coupled #

Slide 35

Slide 35 text

▸ Monster files size > 1500 lines ! ▸ Impossible to test " ▸ Components too coupled # ▸ Hard to understand (and review) classes. $ %&'()*+,

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

CLEAN ARCHITECTURE INDEPENDENT FROM FRAMEWORKS, UI, DATABASE AND EXTERNAL ENTITIES. EASY TO TEST

Slide 39

Slide 39 text

▸ Who will persist the data?

Slide 40

Slide 40 text

▸ Who will persist the data? ▸ And the API interaction?

Slide 41

Slide 41 text

▸ Who will persist the data? ▸ And the API interaction? ▸ Who controls the navigation?

Slide 42

Slide 42 text

Viper

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 45

Slide 45 text

VIPER VIEW, INTERACTOR, PRESENTER, ENTITY, AND ROUTING OBC.IO - VIPER

Slide 46

Slide 46 text

WHY VIPER ❤?

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

VIEW ▸ Shows the content received from the presenter ▸ Notifies user's actions to the presenter ▸ The presenter doesn't know anything about UI

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

PRESENTER ▸ Includes the logic to format the view ▸ Gets the data from the interactor ▸ Receives actions from the view and traduces them into: Navigation actions (wireframe) and Interactor requests

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

INTERACTOR ▸ Associated to an unique use case of the application ▸ Works with PONSO entities ▸ Coordinates both data managers

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

DATAMANAGER ▸ Provider of entities for the Interactor ▸ Responsible of the persistence (Web and Local) ▸ The entities don't know about how to persist themselves

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

WIREFRAME ▸ Initializes the VIPER module ▸ It knows how to navigate ▸ Delegate of transitions animations

Slide 59

Slide 59 text

KEEP IN MIND

Slide 60

Slide 60 text

PROTOCOLS DEPENDENCY INVERSION INTERFACE SEGREGATION (SOLID)

Slide 61

Slide 61 text

STRONG/WEAK BE CAREFUL WITH RETAIN CYCLES ➿ @interface TweetDetailViewController: UIViewController @property (nonatomic, strong) id presenter; @end @interface TweetDetailPresenter: NSObject @property (nonatomic, weak) id view; @end @implementation TweetDetailPresenter - (void)sendTweet:(NSString*)tweet { __weak typeof(self) welf = self; [self.view showLoader]; [self.interactor sendTweetWithCompletion:^(NSError *error) { [welf.view hideLoader]; if (!error) [welf.wireframe moveBack]; }]; } @end

Slide 62

Slide 62 text

ENTITIES DON'T PASS NSMANAGEDOBJECTS! USE PONSOS INSTEAD @interface TweetEntity: NSObject @property (nonatomic, strong) NSString *body; @property (nonatomic, strong) NSString *authorName; @property (nonatomic, strong) NSDate *creationDate; + (TweetEntity*)tweetEntityFromTweet:(Tweet*)tweet; @end

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 65

Slide 65 text

INNER COMMUNICATION

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

OUTER COMMUNICATION

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

WAIT...

Slide 71

Slide 71 text

TESTING

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 74

Slide 74 text

TESTING VIEW

Slide 75

Slide 75 text

TESTING PRESENTER

Slide 76

Slide 76 text

TESTING INTERACTOR

Slide 77

Slide 77 text

TESTING DATAMANAGER

Slide 78

Slide 78 text

Demo

Slide 79

Slide 79 text

TWITTER APP Login and Home views WRITTEN 100% IN SWIFT GITHUB.COM/PEPIBUMUR/VIPER-MODULE-GENERATOR HANEKE, SUGARRECORD, SWIFTER, PURELAYOUT, PROGRESSHUD

Slide 80

Slide 80 text

LOGIN FLOW

Slide 81

Slide 81 text

▸ The VIPER module is initialized and presented by the Wireframe ▸ The view notifies that DidLoad to the Presenter override func viewDidLoad() { self.setupSubviews() self.setupConstraints() self.setNeedsStatusBarAppearanceUpdate() self.presenter?.viewDidLoad() }

Slide 82

Slide 82 text

▸ The Presenter formats the View's content func viewDidLoad() { self.view?.setLoginTitle("Login Twitter") self.view?.setLogo(UIImage(named: "twitter_logo")!) }

Slide 83

Slide 83 text

When the user taps on Login ▸ The View notifies the Presenter func userDidSelectLogin(sender: AnyObject) { self.presenter?.userDidSelectLogin() }

Slide 84

Slide 84 text

The Presenter: ▸ Tells the View to show a loader ▸ Asks the Interactor for Login func userDidSelectLogin() { self.view?.showLoader() self.interactor?.login() { [weak self] (error: NSError?) -> () in if error != nil { // What should we do here? } else { self?.view?.hideLoader() // And here? } } }

Slide 85

Slide 85 text

The Interactor: ▸ Login the user through the APIDataManager ▸ Persists the user's credentials using the LocalDataManager

Slide 86

Slide 86 text

func login(completion: (error: NSError?) -> ()) { self.APIDataManager?.login({ [weak self] (error: NSError?, credentials: TwitterLoginItem?) -> () in if (credentials != nil) { self?.localDatamanager?.persistUserCredentials(credentials: credentials!) completion(error: nil) } else { completion(error: error) } }) }

Slide 87

Slide 87 text

APIDATAMANAGER func login(completion: (error: NSError?, loginItem: TwitterLoginItem?) -> ()) { TwitterClient.requestAccesss { (error, credentials) -> () in if credentials != nil { completion(error: nil, loginItem: TwitterLoginItem(swifterCredentials: credentials!)) } else { completion(error: error, loginItem: nil) } } }

Slide 88

Slide 88 text

LOCALDATAMANAGER func persistUserCredentials(#credentials: TwitterLoginItem) { TwitterAccountManager.persistAccount(fromLoginItem: credentials) }

Slide 89

Slide 89 text

If the login fails ▸ The Presenter asks the View to show an error func showError(let errorMessage: String) { ProgressHUD.showError(errorMessage) } If the login success ▸ The Presenter asks the Wireframe to show the home view

Slide 90

Slide 90 text

Demo

Slide 91

Slide 91 text

INDEX ▸ ViewControllers ▸ VIPER ▸ Communication ▸ Testing ▸ Conclusions

Slide 92

Slide 92 text

SOME CONCLUSIONS ▸ Lighter, more specific and readable classes ▸ Each team member can be working on a different component once the interfaces are defined ▸ There're no excuses for TDD !

Slide 93

Slide 93 text

TIPS ▸ Heavy work but you and you'll team will thank it ▸ Keep in mind the SOLID principles ▸ Refactor your components through iterations ▸ Decouple your code from the database models and data layers

Slide 94

Slide 94 text

RESOURCES ▸ VIPER Module Generator ▸ Objc.io post ▸ Mutual Mobile Engineering blog post ▸ Dobuts/Ideas/Suggestions on Github issues

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

✋DOUBTS?

Slide 97

Slide 97 text

We are hiring!