44
Why do you need to switch from Objective-C to Swift, or let’s talk about ReactiveCocoa v4 Malakhovskyi Vitalii iOS Developer @

Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

  • Upload
    stanfy

  • View
    447

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Why do you need to switch from Objective-C

to Swift, or let’s talk about ReactiveCocoa v4

Malakhovskyi Vitalii iOS Developer @

Page 2: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

- what has been changed since ReactiveCocoa v2

- how to make CocoaTouch reactive 🚀

- a few words about MVVM architecture designed with ReactiveCocoa v4

So what we will talk about:

Page 3: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

What is ReactiveCocoa ?

Page 4: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Hot and Cold

Page 5: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

HOT… — .Next(Void) — .Next(Void) — .Next(Void) — …

… — .Next(Void) — .Next(Void) — .Completed |

COLD| — .Next(data) — Completed |

| — .Error(.ConnectionLost) |

S

S

S

S

Page 6: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Objective-C & ReactiveCocoa v2.5

RACSignal type represents both hot and cold signals.

Page 7: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 8: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Eventspublic enum Event<Value, Error: ErrorType> { case Next(Value) case Failed(Error) case Completed case Interrupted }

Page 9: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Signal<Int, NoError>

Page 10: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 11: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 12: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 13: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

New events prerogatives:• strict types

• generics

• code highlighting

• ErrorType -> NoError

Page 14: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Hot Signal

Page 15: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Cold SignalProducer

Page 16: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

let signal: SignalProducer<Bool, NoError> let observer: Observer<Bool, NoError>

init() { (signal, observer) = SignalProducer.buffer(3)}

signal.startWithNext { value in print(value) } observer.sendNext(true) // true

observer.sendNext(false) // false

observer.sendNext(false) // false

signal.startWithNext { value in print(value) } // true // false // false

Page 17: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Propertiespublic protocol PropertyType { typealias Value

var value: Value { get }

var producer: SignalProducer<Value, NoError> { get } }

Page 18: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

• MutableProperty

• ConstantProperty

• AnyProperty

• DynamicProperty

Properties can be

Page 19: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

KVO vs Property

Page 20: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

class Car: NSObject { dynamic var miles = 0 dynamic var name = "TAZ" }

Page 21: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

class CarObserver: NSObject { private var kvoContext: UInt8 = 1 private let car: Car init(_ car: Car) { self.car = car super.init() car.addObserver(self, forKeyPath: "miles", options: NSKeyValueObservingOptions.New, context: &kvoContext) } override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [String : AnyObject], context: UnsafeMutablePointer<Void>) { if context == &kvoContext { print("Change at keyPath = \(keyPath) for \(object)") } } deinit { car.removeObserver(self, forKeyPath: "miles") } }

Page 22: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

KVO in Swift

• NSObject inheritance - should be Objective-C types - i.e. no structs, enums, and no generics

• dynamic attribute

• cumbersome method signature

Page 23: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

• property <~ signal

• property <~ producer

• property <~ otherProperty

Meet “<~”

Page 24: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Action Action<Input, Output, Error: ErrorType>

Page 25: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

let enabled = MutableProperty(false) enabled <~ combineLatest(self.username.producer, self.password.producer)

.map { return $0.characters.count >= 1 && $1.characters.count >= 1 } signIn = Action<Void, User, NSError>(enabledIf: enabled) {

_ -> SignalProducer<User, NSError> in return self.model.authorize(self.username.value, password: self.password.value)

}

Page 26: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

@IBAction func onSignButtonTap(sender: UIButton) { viewModel.signIn.apply().start()

}

OR

self.action = CocoaAction(viewModel.signIn, input: () )

loginButton.addTarget(action, action: CocoaAction.selector, forControlEvents: UIControlEvents.TouchUpInside )

Page 27: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

loginButton.rac_enabled <~ viewModel.signIn.enabled.producer.takeUntil(rac_willDeallocSignalProducer()) viewModel.signIn.executing.producer .takeUntil(rac_willDeallocSignalProducer()) .startWithNext { [weak self] executing in if executing { self?.activityIndicator.startAnimating() } else { self?.activityIndicator.stopAnimating() } }

Page 28: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Reactive UI

Page 29: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 30: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

func lazyAssociatedProperty<T: AnyObject>(host: AnyObject, key: UnsafePointer<Void>, factory: () -> T) -> T { return objc_getAssociatedObject(host, key) as? T ?? { let associatedProperty = factory() objc_setAssociatedObject(host,

key, associatedProperty, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)

return associatedProperty }() }

func lazyMutableProperty<T>(host: AnyObject, key: UnsafePointer<Void>, setter: T -> (), getter: () -> T) -> MutableProperty<T> { return lazyAssociatedProperty(host, key: key) { let property = MutableProperty<T>(getter()) property.producer.startWithNext { newValue in setter(newValue) } return property } }

https://github.com/vmalakhovskiy/RACExtensions

Page 31: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

struct AssociationKey { static var text: UInt8 = 0 static var textColor: UInt8 = 1 }

extension UILabel { public var rac_text: MutableProperty<String> { return lazyMutableProperty(self,

key: &AssociationKey.text, setter: { self.text = $0 }, getter: { self.text ?? "" })

} public var rac_textColor: MutableProperty<UIColor> { return lazyMutableProperty(self, key: &AssociationKey.textColor, setter: { self.textColor = $0 }, getter: { self.textColor }) } }

Page 32: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

extension UISearchBar: UISearchBarDelegate { public var rac_text: MutableProperty<String> { return lazyAssociatedProperty(self, key: &AssociationKey.text) {

self.delegate = self self.rac_signalForSelector(Selector("searchBar:textDidChange:"), fromProtocol: UISearchBarDelegate.self) .toSignalProducer() .startWithNext({ [weak self] _ in self?.changed() }) let property = MutableProperty<String>(self.text ?? "") property.producer.startWithNext { newValue in self.text = newValue } return property } } func changed() { rac_text.value = self.text ?? "" } }

Page 33: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

MVVM - DEMO

Page 34: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4
Page 35: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Model

ViewModel

View

Page 36: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Modelfunc signIn(login: String, password: String) -> SignalProducer<User, NSError>

ViewModelvar username: MutableProperty<String> { get } var password: MutableProperty<String> { get }var signIn: Action<Void, User, NSError> { get }

View@IBOutlet weak var userNameField: TextFieldWithInset @IBOutlet weak var passwordField: TextFieldWithInset @IBOutlet weak var loginButton: UIButton@IBOutlet weak var activityIndicator: UIActivityIndicatorView

Page 37: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Modelpublic protocol LoginModel { func signIn(login: String, password: String) -> SignalProducer<User, NSError> }

public class LoginModelImpl: LoginModel { let loginManager: LoginManager public init(loginManager: LoginManager) { self.loginManager = loginManager } public func signIn(login: String, password: String) -> SignalProducer<User, NSError> { return loginManager.signIn(login, password: password) }}

Page 38: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

ViewModelpublic protocol LoginViewModel { var username: MutableProperty<String> { get } var password: MutableProperty<String> { get } var signIn: Action<Void, User, NSError>! { get } }

public class LoginViewModelImpl: LoginViewModel { private let model: LoginModel public let username: MutableProperty<String> = MutableProperty("") public let password: MutableProperty<String> = MutableProperty("") public var signIn: Action<Void, User, NSError>! public init(model: LoginModel, initialUsername: String, lastLoginError: NSError?) { self.model = model let enabledSignal = MutableProperty(false) enabledSignal <~ combineLatest(self.username.producer, self.password.producer) .map { return $0.characters.count >= 1 && $1.characters.count >= 1 } signIn = Action<Void, User, NSError>(enabledIf: enabledSignal) { _ -> SignalProducer<User, NSError> in return self.model.signIn(self.username.value, password: self.password.value) } } }

Page 39: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Viewprivate func setupBindings() { viewModel.username <~ userNameField.rac_text.producer.takeUntil(rac_willDeallocSignalProducer()) viewModel.password <~ passwordField.rac_text.producer.takeUntil(rac_willDeallocSignalProducer()) loginButton.rac_enabled <~ viewModel.signIn.enabled.producer.takeUntil(rac_willDeallocSignalProducer()) viewModel..executing.producer .takeUntil(rac_willDeallocSignalProducer()) .startWithNext { [weak self] executing in if executing { self?.activityIndicator.startAnimating() } else { self?.activityIndicator.stopAnimating() } } loginButton.addTarget(action, action: CocoaAction.selector, forControlEvents: UIControlEvents.TouchUpInside) viewModel.signIn.values.observeNext { [weak self] user in } viewModel.signIn.errors.observeNext { [weak self] error in }}

Page 40: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

To sum up:• pure Swift implementation

• updated events

• separating hot and cold signals

• new property feature

• type safety

• much nicer syntax

Page 41: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Щастя! Здоровля!

Page 42: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

Contact me:

purpleshirted crimsongf Vitaliy Malakhovskiy

Page 43: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

https://spin.atomicobject.com/2015/10/26/reactivecocoa-4-differences/

https://github.com/ReactiveCocoa/ReactiveCocoa/tree/master/Documentation

http://nomothetis.svbtle.com/an-introduction-to-reactivecocoa

http://blog.scottlogic.com/2015/05/15/mvvm-reactive-cocoa-3.html

http://blog.scottlogic.com/2015/02/11/swift-kvo-alternatives.html

Page 44: Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or let’s talk about ReactiveCocoa v4

😱https://github.com/vmalakhovskiy/RACExtensions