48
Dependency Injection + iOS Michał Karpowicz www.softwarehut.pl 1

Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

Embed Size (px)

Citation preview

Page 1: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 1

Dependency Injection + iOSMichał Karpowicz

Page 2: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 2

00WSTĘP

Page 3: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 3

1.Dependency Injection2.TDD3.DYI4.Typhoon

Page 4: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 4

Projekt

• Dwa View Controllery – DashboardViewController i CustomersViewController• CustomersDataSource• CustomerService• SessionManager

Page 5: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 5

01Dependency Injection

Page 6: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 6

Inversion of Control

Page 7: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 7

Cele

•Podział na moduły•Rozszerzalność

Page 8: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 8

Dependency Injection

class CustomersDataSource: NSObject { let service: CustomerService override init() { service = CustomerService(manager: SessionManager(baseUrl: "https://api.customer.com", configuration: NSURLSessionConfiguration(), timeout: 30)) } }

Page 9: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 9

Dependency Injection

Page 10: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 10

Rodzaje DI

•Extract and override•Method injection•Property injection•Constructor injection

Page 11: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 11

DEPENDENCY INJECTION?

import UIKitimport Foundation

class UserCredentials { private let authorizationTokenKey = "AuthorizationTokenKey" func getAuthorizationToken() -> String { let value = NSUserDefaults.standardUserDefaults().stringForKey(authorizationTokenKey) guard let retVal = value else { return "" } return retVal }}

Page 12: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 12

EXTRACT AND OVERRIDE

private let authorizationTokenKey = "AuthorizationTokenKey" func getAuthorizationToken() -> String { let value = userDefaults().stringForKey(authorizationTokenKey) guard let retVal = value else { return "" } return retVal } func userDefaults() -> NSUserDefaults { return NSUserDefaults.standardUserDefaults() }

Page 13: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 13

METHOD INJECTION

private let authorizationTokenKey = "AuthorizationTokenKey" func getAuthorizationToken(userDefaults userDefaults: NSUserDefaults) -> String { let value = userDefaults.stringForKey(authorizationTokenKey) guard let retVal = value else { return "" } return retVal }

Page 14: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 14

PROPERTY INJECTION

class UserCredentials { var userDefaults: NSUserDefaults! private let authorizationTokenKey = "AuthorizationTokenKey" func getAuthorizationToken() -> String { let value = userDefaults.stringForKey(authorizationTokenKey) guard let retVal = value else { return "" } return retVal }}

let credentials = UserCredentials()credentials.userDefaults = NSUserDefaults.standardUserDefaults()

Page 15: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 15

CONSTRUCTOR INJECTION

private let userDefaults: NSUserDefaults private let authorizationTokenKey = "AuthorizationTokenKey" init(userDefaults: NSUserDefaults) { self.userDefaults = userDefaults } func getAuthorizationToken() -> String { let value = userDefaults.stringForKey(authorizationTokenKey) guard let retVal = value else { return "" } return retVal }

let credentials = UserCredentials(NSUserDefaults.standardUserDefaults())

Page 16: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 16

Dependency Injection

class CustomersDataSource: NSObject { let service: CustomerService override init() { service = CustomerService(manager: SessionManager(baseUrl: "https://api.customer.com", configuration: NSURLSessionConfiguration(), timeout: 30)) } }

Page 17: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 17

Dependency Injection

let service: CustomerService init(customerService: CustomerService) { service = customerService }

Page 18: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 18

Dependency Injection

• Niezmienność obiektów• Klasy łatwe do testowania

Page 19: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 19

02TDD

Page 20: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 20

TDD

TDD + Dependency Injection = <3

Page 21: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 21

TDD

Networking Tests

Page 22: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 22

TDD

Response mock

class MockGETSessionManager: NSObject, SessionManagerProtocol { var success: ((AnyObject) -> ())! func GET(url: String, parameters: AnyObject?, success: (AnyObject) -> (), failure: () -> ()) { self.success = success } }

protocol SessionManagerProtocol { func GET(url: String, parameters: AnyObject?, success: (AnyObject) -> (), failure: () -> ())}

Page 23: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 23

TDD

Testowanie mockafunc testMockGET() { let mockSessionManager = MockGETSessionManager() let customerService = CustomerService(sessionManager: mockSessionManager) let customerDataSource = CustomersDataSource(customerService: customerService) customerDataSource.fetchData() mockSessionManager.success(NSData()) XCTAssertNotNil(customerDataSource.customers) }

Page 24: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 24

TDD

Frameworki• OCMockito (Objective-C) - https://github.com/jonreid/OCMockito• Mockingjay (Swift) - https://github.com/kylef/Mockingjay

Page 25: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 25

03DYI

Page 26: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 26

DIY

Page 27: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 27

DIY

class Injector: NSObject { func dashboardViewController() -> DashboardViewController { let viewController = DashboardViewController() viewController.injector = self return viewController }}

Page 28: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 28

DIY

class AppDelegate: UIResponder, UIApplicationDelegate {

/…/let injector = Injector()

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

window?.rootViewController = injector.dashboardViewController() return true }/.../}

Page 29: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 29

DIY

func sessionManager() -> SessionManager { let sessionManager = SessionManager(baseUrl: "https://api.customer.com", configuration: NSURLSessionConfiguration(), timeout: 30) return sessionManager} func customerService() -> CustomerService { let customerService = CustomerService(sessionManager: sessionManager()) return customerService}func customerDataSource() -> CustomersDataSource { let dataSource = CustomersDataSource(customerService: customerService()) return dataSource }func customersViewController() -> CustomersViewController { let viewController = CustomersViewController() viewController.injector = self viewController.dataSource = customerDataSource() return viewController}

Page 30: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 30

DIY

class DashboardViewController: UIViewController {

/.../

func showCustomersView() { let viewController = injector?.customersViewController() navigationController?.pushViewController(viewController!, animated: true) }}

Page 31: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 31

04TYPHOON

Page 32: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 32

Typhoon?

http://typhoonframework.org/

• Nie inwazyjny• Wsparcie constructor i property injection• Wstrzykiwanie view controllerów• Integracja ze storyboardami• Minimalne obciążenie CPU• Battle-tested• Aktywnie rozwijany• “Swift”!

Page 33: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 33

Typhoon - Podstawy

1.Assembly – TyphoonAssembly2.Definition – TyphoonDefinition

Page 34: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 34

Typhoon - Setup

1.Instalacja2.Stworzenie ApplicationAssembly – subclass TyphoonAssembly3.Dodanie listy TyphoonInitialAssembies do Info.plis

That’s it!

Page 35: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 35

Typhoon - Instalacja

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '8.0'

use_frameworks!

target 'DI-Typhoon' do pod 'Typhoon'End

Podfile:

pod installTerminal:

Page 36: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 36

Typhoon – ApplicationAssembly

import Typhoon

class ApplicationAssembly: TyphoonAssembly { dynamic func appDelegate() -> AnyObject { return TyphoonDefinition.withClass(AppDelegate.self) { definition in } }}

Page 37: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 37

Typhoon

Real life scenario

Page 38: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 38

Typhoon – Projekt startowy

Lista TyphoonAssemblies:• ApplicationAssembly• ViewControllerAssembly• DataSourceAssembly• CoreServicesAssembly

Page 39: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 39

ApplicationAssembly

class ApplicationAssembly: TyphoonAssembly { var viewControllerAssembly: ViewControllerAssembly! dynamic func appDelegate() -> AnyObject { return TyphoonDefinition.withClass(AppDelegate.self) { definition in definition.injectProperty("viewControllerAssembly", with: self.viewControllerAssembly) } }}

Page 40: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 40

ViewControllerAssembly

class ViewControllerAssembly: TyphoonAssembly { var dataSourceAssembly: DataSourceAssembly! dynamic func customersViewController() -> AnyObject { return TyphoonDefinition.withClass(CustomersViewController.self) { definition in definition.useInitializer("init") { initializer in } definition.injectProperty("dataSource", with: self.dataSourceAssembly.customerDataSource()) definition.injectProperty("viewControllerAssembly", with: self) } } /.../}

Page 41: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 41

DataSourceAssembly

class DataSourceAssembly: TyphoonAssembly { var coreServicesAssembly: CoreServicesAssembly! dynamic func customerDataSource() -> AnyObject { return TyphoonDefinition.withClass(CustomersDataSource.self) { definition in definition.useInitializer("initWithCustomerService:") { initializer in initializer.injectParameterWith(self.coreServicesAssembly.customerService()) } } }}

Page 42: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 42

CoreServicesAssembly

dynamic func sessionManager() -> AnyObject { return TyphoonDefinition.withClass(SessionManager.self) { definition in definition.useInitializer("initWithBaseUrl:configuration:timeout:") { initializer in initializer.injectParameterWith("https://api.customer.com") initializer.injectParameterWith(NSURLSessionConfiguration()) initializer.injectParameterWith(30) } } }dynamic func customerService() -> AnyObject { return TyphoonDefinition.withClass(CustomerService.self) { definition in definition.useInitializer("initWithSessionManager:") { initializer in initializer.injectParameterWith(self.sessionManager()) } } }

Page 43: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 43

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {

/…/var viewControllerAssembly: ViewControllerAssembly!

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

window?.rootViewController = viewControllerAssembly.dashboardViewController() as! DashboardViewController return true }/.../}

Page 44: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 44

Typhoon

Dlaczego “Swift”?

Page 45: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 45

Typhoon

Page 46: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 46

PYTANIA?

Page 47: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 47

PYTANIA I CHABORY

Page 48: Mobile Bialystok #5 Dependency Injection iOS @Michał Karpowicz

www.softwarehut.pl 48

DZIĘKUJĘ ZA UWAGĘ

Siedziba firmy:Sienkiewicza 11015-005 Białystok