74
Três conceitos que farão a diferença nos seus apps

Três conceitos que farão a diferença nos seus apps

Embed Size (px)

Citation preview

Três conceitos que farão a diferença nos seus apps

• Networking e storage

• Diffing

• Navegação entre telas

MDPMy Design Pattern

Abstração

Offline ControllersFui usar o app em modo avião e olha no que deu

ViewController.swift

ViewController.swift

ViewController

ViewController

View Controller

Data Provider

Storage Controller API Client

API Client

View Controller

Data Provider

Storage Controller API Client

Storage Controller

View Controller

Data Provider

Storage Controller API Client

Data Provider

View Controller

Data Provider

Storage Controller API Client

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

HTTPJSON

SERVIDOR

APIREALM OBJECTS

REALM

SUBSCRIBE [USERS]

final class DataProvider { init(client: APIClient, storage: Storage) { self.client = client self.storage = storage } /// ... }

protocol APIClient { func searchUsers(query: String, completion: @escaping (Result<SearchResults<User>, APIError>) -> ()) func user(with login: String, completion: @escaping (Result<User, APIError>) -> ()) func repositories(by login: String, completion: @escaping (Result<[Repository], APIError>) -> ()) func repository(by login: String, named name: String, completion: @escaping (Result<Repository, APIError>) -> ()) func stargazers(for repositoryName: String, ownedBy login: String, completion: @escaping(Result<[User], APIError>) -> ()) }

protocol Storage: class { func store(users: [User], completion: ((StorageError?) -> ())?) func store(repositories: [Repository], completion: ((StorageError?) -> ())?) func searchUsers(with query: String) -> Observable<[User]> func user(withLogin login: String) -> Observable<User> func user(withId id: String) -> Observable<User> func repositories(by user: User) -> Observable<[Repository]> func repository(named name: String) -> Observable<Repository> func repository(withId id: String) -> Observable<Repository> func stargazers(for repository: Repository) -> Observable<[User]> }

DiffingCalculando diferenças entre coleções de models

struct Repository { let id: Int let name: String let owner: User let stars: Int }

id: 1 name: repoA owner: {insidegui} stars: 100

id: 2 name: repoB owner: {insidegui} stars: 200

let repositories: [Repository]

0

1

id: 1 name: repoA owner: {insidegui} stars: 102

id: 2 name: repoB owner: {insidegui} stars: 200

let repositories: [Repository]

0

1

id: 1 name: repoA owner: {insidegui} stars: 102

id: 2 name: repoB owner: {insidegui} stars: 200

difference = [.modified(0)]

0

1

id: 1 name: repoA owner: {insidegui} stars: 100

id: 2 name: repoB owner: {insidegui} stars: 200

0

1

id: 3 name: repoC owner: {insidegui} stars: 300

id: 2 name: repoB owner: {insidegui} stars: 200

let repositories: [Repository]

0

1

id: 3 name: repoC owner: {insidegui} stars: 300

id: 2 name: repoB owner: {insidegui} stars: 200

difference = [.deleted(0), .added(0)]

0

1

id: 1 name: repoA owner: {insidegui} stars: 102

id: 2 name: repoB owner: {insidegui} stars: 200

0

1

X

Levenshtein

let diff = IGListDiffPaths(0, 0, oldData, newData, .equality) tableView.beginUpdates() tableView.insertRows(at: diff.inserts, with: .automatic) tableView.deleteRows(at: diff.deletes, with: .automatic) tableView.reloadRows(at: diff.updates, with: .none) tableView.endUpdates()

extension UITableView { func reload(oldData: [IGListDiffable], newData: [IGListDiffable]) { let diff = IGListDiffPaths(0, 0, oldData, newData, .equality) beginUpdates() insertRows(at: diff.inserts, with: .automatic) deleteRows(at: diff.deletes, with: .automatic) reloadRows(at: diff.updates, with: .none) endUpdates() } }

RoutersConectando seus view controllers sem perder a sanidade

#comofas?

SEGUES

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "showRepositories" { if let vc = segue.destination as? RepositoriesViewController { vc.user = self.user } } }

init(provider: DataProvider, user: User, delegate: RepositoriesViewControllerDelegate)

Dependency Injection

final class AppRouter {

init(appLaunchOptions: [UIApplicationLaunchOptionsKey : Any]?)

func showInitialViewController()

func showRepositoriesViewController(for user: User)

func showStargazersViewController(for repository: Repository)

func showProfileViewController(for user: User, from presenting: UIViewController? = nil) }

AppRouter.swift

class AppDelegate: UIResponder, UIApplicationDelegate {

var router: AppRouter! func application(..., didFinishLaunching:...) -> Bool { router = AppRouter(appLaunchOptions: launchOptions) router.showInitialViewController() return true } }

func showInitialViewController() { if preferences.needsMigration { showMigrationViewController(with: "Migrating, please wait") storage.migrate(completion: showSearchViewController) } else { showSearchViewController() } }

extension AppRouter: UsersTableViewControllerDelegate { // ... }

extension AppRouter: RepositoriesTableViewControllerDelegate { // ... }

override func tableView(..., didSelectRowAt...) { delegate?.usersTableViewController(self, didSelect: ...) }

func usersTableViewController(_ controller: ..., didSelect user: User) { if controller is SearchUsersViewController { showRepositoriesViewController(for: user) } else if controller is StargazersViewController { showProfileViewController(for: user) } }

OBRIGADO!

Guilherme Rambo

github.com/insidegui

Twitter: @_inside Github: github.com/insidegui