DISTRIBUTING INFORMATION AGENDA What does information distribution - - PowerPoint PPT Presentation

distributing information agenda
SMART_READER_LITE
LIVE PREVIEW

DISTRIBUTING INFORMATION AGENDA What does information distribution - - PowerPoint PPT Presentation

DISTRIBUTING INFORMATION AGENDA What does information distribution mean? Delegation Closures Notifications Property Observers Bindings / Key Value Observation INFORMATION DISTRIBUTION Mobile apps are highly interactive Multiple interfaces


slide-1
SLIDE 1
slide-2
SLIDE 2

DISTRIBUTING INFORMATION

slide-3
SLIDE 3

AGENDA

What does information distribution mean? Delegation Closures Notifications Property Observers Bindings / Key Value Observation

slide-4
SLIDE 4

INFORMATION DISTRIBUTION

Mobile apps are highly interactive Multiple interfaces drive data changes: UI Network Main task is responding to events and distributing new data

slide-5
SLIDE 5

CODE LOCALITY

Each piece of code needs well defined responsibility Example: 
 The code that triggers 
 network request is not 
 necessarily the code that 
 is interested in response

EntryView FolderView update Image download Button Tapped

downloadImage

(1) (2) (3)

Image OtherView update Image

slide-6
SLIDE 6

TYPE TO TYPE COMMUNICATION

slide-7
SLIDE 7

TYPE TO TYPE COMMUNICATION

class UserViewController: UIViewController { func infoButtonTapped() { // communicate with business logic } } class UserView { var userViewController: UserViewController? func infoButtonTapped() { userViewController?.infoButtonTapped() } }

Tight coupling!

slide-8
SLIDE 8

TYPE TO TYPE COMMUNICATION

func infoButtonTapped() //… init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) var view: UIView! func loadView() var nibName: String? { get } var nibBundle: NSBundle? { get } var storyboard: UIStoryboard? { get } //…

The UserView could call any method provided by UserViewController, including all the ones inherited from UIView Controller UserView can become dependent on UIViewController UserView has to deal with huge interface:

slide-9
SLIDE 9

TYPE TO TYPE COMMUNICATION

Typically used to establish a life long connection Easy to use Results in tight coupling No tight interface for communication between two types Mostly only useful for 1-1 communication

slide-10
SLIDE 10

DELEGATION

slide-11
SLIDE 11

DELEGATION

Create a formal protocol that describes the communication interface Use this protocol to create an indirect connection between the two types

slide-12
SLIDE 12

DELEGATION

class UserView { var delegate: UserViewResponder? func infoButtonTapped() { responder?.infoButtonTapped() } }

Indirection = looser coupling

class UserViewController: UIViewController, UserViewResponder { func infoButtonTapped() { // communicate with business logic } } protocol UserViewResponder { func infoButtonTapped() }

slide-13
SLIDE 13

DELEGATION

Typically used to establish a life long connection Decouples communication, easy to replace delegate with any other type conforming to protocol Tight interface that contains only methods that are relevant for this specific communication channel Mostly only useful for 1-1 communication

slide-14
SLIDE 14

CLOSURES

slide-15
SLIDE 15

CLOSURES

class APIClient { func userDetails(userId: String, callback: UserDetailsCallback) { // network request callback(user) } }

Indirection = looser coupling

class UserViewController: UIViewController {

  • verride func viewDidAppear(animated: Bool) {

APIClient().userDetails("13") { user in // do something with user } } }

typealias UserDetailsCallback = User? -> ()

slide-16
SLIDE 16

CLOSURE GOTCHAS

Code locality

class UserViewController: UIViewController {

  • verride func viewDidAppear(animated: Bool) {

super.viewDidAppear(animated) 
 APIClient().userDetails("13") { user in // do something with user } } }

Code locality

class UserViewController2: UIViewController {

  • verride func viewDidAppear(animated: Bool) {

super.viewDidAppear(animated) APIClient().userDetails("13", callback: receivedUser) } func receivedUser(user: User?) { // do something with user } }

slide-17
SLIDE 17

CLOSURE GOTCHAS

Retain Cycles

class UserViewController: UIViewController { var callback: UserDetailsCallback?

  • verride func viewDidAppear(animated: Bool) {

callback = { user in self.showUser(user) } } func showUser(user: User?) { //... } }

Object retains the callback Callback retains the object through self reference Results in retain cycle

slide-18
SLIDE 18

CLOSURE GOTCHAS

No Retain Cycles

class UserViewController: UIViewController { var callback: UserDetailsCallback?

  • verride func viewDidAppear(animated: Bool) {

callback = { [unowned self] user in self.showUser(user) } } func showUser(user: User?) { //... } }

Use capture list to capture self weakly Callback will no longer retain self

Breaks retain cycle!

slide-19
SLIDE 19

CLOSURES

Typically used for short lived relationships Decouples communication Provides a communication interface with only a single function Requires caution regarding code locality Need to be careful to avoid retain cycles

slide-20
SLIDE 20

NOTIFICATIONS

slide-21
SLIDE 21

NOTIFICATIONS

Notifications allow us to broadcast information (1 to N) Sender has no information about which objects have subscribed to notifications

slide-22
SLIDE 22

NOTIFICATIONS

func synchronize() { // network request NSNotificationCenter.defaultCenter().postNotificationName( "MyApp.SynchronizationCompleted",

  • bject: self)

}

Posting a notification:

Notifications are delivered on the same thread on which they are posted! Optionally you can use a userData argument to attach arbitrary data to the notification

slide-23
SLIDE 23

NOTIFICATIONS

class Listener { init() { NSNotificationCenter.defaultCenter().addObserver(self, selector: "syncComplete", name: nil, object: nil) } @objc func syncComplete() { // work print("ok") } }

Registering for Notifications:

Specify which notification you want to listen to Specify which method on which object should be called once this notification

  • ccurs

Mark the target method with @objc if you are not subclassing from an Objective-C object

slide-24
SLIDE 24

NOTIFICATION GOTCHAS

Don’t forget to unsubscribe!

class Listener { deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } //… }

If a deallocated object is registered with the notification center, your app will crash on an attempt to deliver a notification to the dead object

class UserViewController: UIViewController {

  • verride func viewDidDisappear(animated: Bool) {

super.viewDidDisappear(animated) NSNotificationCenter.defaultCenter().removeObserver(self) } }

slide-25
SLIDE 25

NOTIFICATIONS

Used for broadcasting information Easy to communicate with different parts of the program without explicit references No well defined communication interface / no type information Causes crashes if you forget to unregister Can create dependencies between code that should not be coupled

slide-26
SLIDE 26

PROPERTY OBSERVERS

slide-27
SLIDE 27

PROPERTY OBSERVERS

class UserViewController: UIViewController { var label: UILabel! var user: User? { didSet { if let label = label, let user = user { label.text = user.name } } } }

Implicitly propagate changes within an instance of a type

slide-28
SLIDE 28

PROPERTY OBSERVERS

Used for information propagation within an instance Easy to use, type safe Not applicable in many scenarios

slide-29
SLIDE 29

BINDINGS / KEY VALUE OBSERVATION

slide-30
SLIDE 30

KEY VALUE OBSERVATION (KVO)

Objective-C API that relies on the Objective-C Runtime Generates notifications when an observed property on an observed object changes Think: property observers for other objects

slide-31
SLIDE 31

KVO

class Observer: NSObject { var user: User init(user: User) { self.user = user super.init() self.user.addObserver(self, forKeyPath: "name", options: NSKeyValueObservingOptions.New, context: nil) }

  • verride func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context:

UnsafeMutablePointer<Void>) { if let newValue = change?[NSKeyValueChangeNewKey] { print("Name changed: \(newValue)") } else { super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) } } deinit { self.user.removeObserver(self, forKeyPath: "name") } }

API was not designed for Swift!

slide-32
SLIDE 32

KVO

Used to observe changing values on other objects Allows observation of (almost) any property without additional work

  • n class that is being observed

API doesn’t provide type information of observed values API is arcane, e.g. one callback for all observer properties Not available on Swift classes, need to inherit from NSObject and use the dynamic keyword

slide-33
SLIDE 33

KVO / BINDINGS

Swift doesn’t have it’s own KVO mechanism, but there are third party alternatives and it’s easy to implement your own KVO alternative [1] One framework that provides KVO and Binding capabilities is Bond [2]

[1]: Exploring KVO Alternatives with Swift [2]: Summer Academy lecture discussing Bond

slide-34
SLIDE 34

DYNAMIC PROPERTIES IN BOND

var image: Observable<UIImage?> = Observable(nil) image.value = otherImage

Declaring an Observable property: Setting an Observable property:

slide-35
SLIDE 35

OBSERVING NEW VALUES

post.likes.observe { [unowned self] users in self.likingUsers = users //… }

Calls callback whenever new value is available:

slide-36
SLIDE 36

OBSERVING NEW VALUES

post.image.bindTo(postImageView.bnd_image)

Updates image view whenever new value is available:

slide-37
SLIDE 37

BONDS

Used to observe changing values on other objects Allows observation of (almost) any property without much additional work on class that is being observed Communication protocol is implicit, harder to understand for other developers

slide-38
SLIDE 38

SUMMARY

Delegation Closures Notifications Property Observers Bindings / Key Value Observation

slide-39
SLIDE 39

ADDITIONAL RESOURCES

NSNotificationCenter class reference Swift Language Reference: Property Observers NSHipster: Key-Value Observing Exploring KVO Alternatives with Swift Bond Framework on Github