DISTRIBUTING INFORMATION AGENDA What does information distribution - - PowerPoint PPT Presentation
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
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 drive data changes: UI Network Main task is responding to events and distributing new data
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
TYPE TO TYPE COMMUNICATION
TYPE TO TYPE COMMUNICATION
class UserViewController: UIViewController { func infoButtonTapped() { // communicate with business logic } } class UserView { var userViewController: UserViewController? func infoButtonTapped() { userViewController?.infoButtonTapped() } }
Tight coupling!
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:
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
DELEGATION
DELEGATION
Create a formal protocol that describes the communication interface Use this protocol to create an indirect connection between the two types
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() }
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
CLOSURES
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? -> ()
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 } }
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
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!
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
NOTIFICATIONS
NOTIFICATIONS
Notifications allow us to broadcast information (1 to N) Sender has no information about which objects have subscribed to notifications
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
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
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) } }
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
PROPERTY OBSERVERS
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
PROPERTY OBSERVERS
Used for information propagation within an instance Easy to use, type safe Not applicable in many scenarios
BINDINGS / KEY VALUE OBSERVATION
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
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!
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
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