This document provides an overview of key concepts in iOS development. It discusses topics like the iOS architecture, UIViewController, Core Animation, Core Data, networking with NSURLSession and AFNetworking, collection classes, property attributes, and supporting multiple device generations and chip architectures. It also covers memory management techniques, state preservation, multitasking capabilities, and using static libraries.
7. Xcode 5
Accounts Pane in Preferences
●
configure Apple accounts, source repositories and CI servers
Capabilities Settings in Project
●
configure platform features
XCTest
●
default for new projects
Continuous Integration
●
Bots, requires OS X Server
Debugger
●
Gauges
Documentation
Sprite Kit Support
8. Instruments
Time Profiler
●
●
find bottlenecks and refactor them
common issue: network activity is blocking UI thread
Allocations
●
●
track unbounded memory growth with heap shots
common issue: cache needs to be cleared when system throws warning
Leaks
●
●
find unreferenced objects eating up memory
common issue: CoreFoundation objects like CGContextRef, CGImageRef
9. iOS 7 New Foundations
NSArray
●
added 'firstObject'
NSData
●
added Base64 support
NSTimer
●
added 'tolerance' property to allow system flexibility to increase power
savings and responsiveness
NSProgress
●
entirely new class for task monitoring
10. iOS 7 Motion
Motion Effects
●
●
●
add subtle depth to UI as device moves
UIInterpolatingMotionEffect subclasses UIMotionEffect
group 2 (eg. x and y) with UIMotionEffectGroup and add to view [view addMotionEffect:myGroup]
Dynamics
●
add physics-like effects to enhance views (not make games)
Custom Transitions
●
●
●
protocol based API for flexibility, transition animations happen in OS sandbox
VC asks transitioning delegate for animated transitioning object
OS tells ATO to perform animation, ATO tells context when complete, context tells OS
Interactive Transitions
●
●
●
●
●
animation completes transition after the interaction ends, if your params are satisfied (dragged 30%)
UIPercentDrivenInteractiveTransition
VC asks transitioning delegate for animated transitioning object and interactive transitioning object
OS tells ITO to listen for interaction, ITO updates context, ITO tells context to finish or cancel
OS tells ATO perform animation, ATO tells context when complete, context tells OS
11. iOS 7 UIViewController
Extended Layout
●
●
●
content fills entire screen, underlaps status bar, affects scrollviews
self.edgesForExtendedLayout defaults to UIRectEdgeAll (use UIRectEdgeNone for previous behavior)
self.automaticallyAdjustScrollViewInsets defaults to YES
Status Bar
●
●
●
●
●
●
●
no longer has a background
can specify style per view controller (previous OS required going through the app delegate)
UIStatusBarStyleDefault has black icons
UIStatusBarStyleLightContent has white icons
can prompt the VC to re-ask for status bar style and hide/show, for multiple states in a VC
wrap call to [self setNeedsStatusBarUpdate] in UIView animation block for an animated hide/show
can change default status bar animation
12. iOS 7 JavaScript Core
Run JS from Obj-C and vice versa
●
●
●
●
without UIWebView
seamlessly pass values and objects
hybrid objects are possible
○ an obj-c button with a JS handler
○ an obj-c object with JS properties or methods
JS is interpreted at runtime
○ potential for real time code changes
Cannot be used to execute
●
●
downloaded JS
end user composed JS
13. iOS 7 TextKit
Prior to iOS 6, web views were used to render text with mixed styles
Attributed String was added in iOS 6, but that still used a web view
Core Text was the only option for advanced layout and multiline text
iOS 7 gives us TextKit, built on top of Core Text
●
●
●
●
●
underlies UILabel, UITextView, UITextField
provides dynamic type: app must conform to user-selected font sizes weights
adds letterpress effects for depth effects
includes exclusion paths for flowing text around complex paths and shapes
enables dynamic formatting based on the text itself
14. Benefits of A7
Apple A7 is the first 64-bit architecture on a mobile device
●
●
●
●
●
Much larger address space
Support for OpenGL ES 3.0
Re-compile existing apps for a performance boost
Performance enhancements come from
○ Double the int/fp registers
○ More efficient Assembly Code
○ Runtime optimizations
○ Much higher precision for longs and floats
■ NSInteger
■ CGFloat
Same 64-bit standard as OS X, making apps more portable
15. Implications of A7
Adopting 64-bit
●
●
●
update architectures in project settings
update any libraries, library architectures must match project
○ in terminal run $ file mylibrary.a to see architectures library has been compiled for
fix issues and test
App Edits
●
●
●
●
Be sure to maintain consistency with types
○ eg. int myVar = [someObject integerValue] should be NSInteger myVar = …
Use the sizeof(type) instead of hardcoding to provide the correct size for the architecture
Make sure format specifiers match the data type when formatting strings
Care required for sharing data between devices and iCloud restore
○ Always read what you write: 3 strategies
■ Always write 32 bit values
■ Always write 64 bit values
■ Include file metadata to describe contents
16. The M7 Motion Coprocessor
Monitors motion, all the time
●
●
continuously
inexpensively
Combines functions
●
●
●
Compass
Accelerometer
Gyroscope
CMMotionActivityManager
●
●
periodic motion updates
motion data by date range
CMStepCounter
●
provide a block to be invoked as user takes steps
18. Application States
State
Description
Not Running
App has not been launched or was terminated
Inactive
App is in foreground, but not receiving events. A brief, transitional state.
Active
App is in the foreground and is receiving events.
Background
App is in background and executing code. Usually, a brief, transitional state. Apps can
request additional execution time. App can launch directly into this state.
Suspended
App is in background, but not executing code. App may be terminated at-will by the
system to make more room in memory.
19. Manual Memory Management
Manual Memory Management
●
●
●
●
you own any object you create
you can take ownership of an object using retain
when no longer needed, you must release ownership
never release an object you don't own
Children and connectors should never retain a parent or ancestor
●
use a weak reference for
○ 'self' or any other parent objects needed in a block
○ delegate properties
○ IBOutlet properties
○ objects to which observers are added
20. ARC
Released in iOS 5
Compiler inserts retain and release code for you
All we need to do is create pointers to objects we want to keep around
ARC does not eliminate all possible leaks
We still need to manually manage some stuff
●
●
●
Core Foundation, Core Graphics
C objects managed by malloc() and free()
retain cycles, references in blocks
21. Multitasking
iOS 4
iOS 5
iOS 6
iOS 7
app can register to run
specific services in
background
Home button suspends
app, rather than
terminate it
state preservation and
restoration
periodic downloads to
update app
iOS 7 Introduces
●
●
●
background fetch
○ removes wait and refresh on relaunch
background transfer
○ lengthy up/downloads continue unhindered in background
silent push notifications
○ trigger a background fetch
22. Background
Apps can continue running in the background to:
●
●
●
●
●
play audio
get location updates
get new issues for Newsstand apps
handle VoIP calls
run arbitrary code for finite time
○ uses API, not declared in .plist like the others
○ no guarantee on amount of time granted
23. Persistence
NSUserDefaults
●
●
small amount of data
key-value pairs, dictionaries, arrays
.plist files
●
●
small amount of data
dictionary, array
Core Data
●
●
●
large amount of data
related tables
app state preservation
24. State Preservation & Restoration
App preservation responsibilities
●
●
●
App-Delegate must opt-in, tell UIKit app supports state preservation
tell UIKit which view controllers and views should be preserved
encode data for preserved objects
App restoration responsibilities
●
●
●
●
tell UIKit that the app supports state restoration
provide or create the objects requested by UIKit
decode preserved state data
return objects to previous state
25. Core Data
Wrapper for SQLite DB
●
●
●
●
NSManagedObject
○ represents an element that gets stored
○ a single record/row in a table
○ a dictionary accessed with 'valueForKey' and 'setValue:forKey:'
NSManagedObjectContext
○ a collection of managed objects
○ handles creating, working with and saving managed objects
NSManagedObjectModel
○ defines managed objects
○ entities (tables), attributes (fields), validations, relationships
NSPersistentStoreCoordinator and NSPersistentStore
○ interact directly with the SQLite DB
26. Core Animation
Used to animate views and visual elements using the GPU.
Layers are at the heart of the graphics manipulation infrastructure.
Most animation involve the modification of layer properties
●
●
implicit animations happen when you change the property
explicit animations
○ make an animation object
○ add animation to the layer
○ change the layer property
Key frame animations
●
●
●
enables you to define an animation that follows a path
path can be defined by an array of values or a CGPathRef
timing can be controlled with calculationMode, keyTimes, and timingFunctions
27. UIViewController
Provides fundamental view-management
●
●
●
resizes and lays out views
adjusts content of views
acts on behalf of views for user interactions
iOS 6 gave us UICollectionViewController
●
●
powerful, flexible way to present ordered data
similar to table view delegate and data source
○ UICollectionView contains UICollectionViewCells
○ supplementary views live outside cells, but contain useful data
○ decoration views enhance visual appearance
○ UICollectionViewLayout defines cell layout within view
28. Support Multiple SDKs & Chips
●
●
●
●
●
Frameworks and Classes
○ make later frameworks optional in linkage settings
○ messages to nil are ok for [NewClass alloc] i.e. [nil alloc]
○ but, usage of class constants used as parameters need to be wrapped
○ eg. "if(UINewClassConstant != nil){[SomeObject someMessage:UINewClassConstant]}"
Methods
○ usage of latest methods need to be wrapped
○ by 'if [class respondsToSelector:@selector(newMethod:)]'
Hardware Capabilities
○ need to be checked with 'is...Available' booleans
UI Designs
○ need to check by comparing NSFoundationVersionNumber to provided constants
○ eg. if(NSFoundationVersionNumber == NSFoundationVersionNumber_iOS_6_1)
Hardware Architectures
○ rare, but possible to compile different code for different CPUs using preprocessor directives
○ eg. #if __LP64__ …[64 bit code]... #else …[32 bit code]... #endif
29. Static Libraries
Bundle common classes for shared use
Centralize common code for ease of maintenance
Share a library without allowing access to see the code
Make a version snapshot of a library that develops over time
Wrap non-ARC code for linking with ARC project
Use lipo to create a universal binary (to support multiple architectures)
Two ways to include library in project
●
●
reference the headers and the binary .a file directly
○ add a Header Search Path to location of headers
○ in project Build Phases, link the binary
include the library project as a subproject
30. NSURLSession
Replacement for NSURLConnection
Tasks perform all the work for most common use cases: data, upload,
download
Adopted by latest version of AFNetworking
Features
●
●
●
●
●
background upload/download
pause resume network operations
configurable container for requests
is subclassable and offers private storage
authentication handled per session by delegate
31. AFNetworking
Most popular 3rd party library
Latest version utilizes NSURLSession
Provides data type classes for handling response data
●
●
this means completion block provides parsed data in format requested
unlike NSURLSession, where you would need to convert as needed
32. Collection Classes
NSArray
●
reliably record order of elements
NSDictionary
●
model relationships between pairs of objects
NSSet
●
efficient membership checking and set operations (union, intersect)
http://rypress.com/tutorials/objective-c/data-types/nsset.html
33. Property Attributes
atomic
default
for objects. not a keyword, assumed when nonatomic not present. creates a lock and increases the
retain count to ensure read/write safety. decreases performance and we still need to implement threadsafety.
strong (retain)
default
for objects. claims ownership of property. all instance and local variables are strong by default.
for objects. indicates a Zeroing Weak Reference. property is not retained. generally used for IBOutlets
and objects that only exist as long as the parent exists, or if some other object has a strong reference.
weak
readwrite
default
readonly
assign
for all properties. a getter and a setter will be synthesized for the property.
for all properties. a setter will not be synthesized for the property.
default
for primitives. synthesizes getter/setter without retaining.
nonatomic
for objects. multiple threads can access a nonatomic property, so it not read/write safe, but it is more
performant than atomic.
unsafe_unretained
for use in ARCLite environments. is an ownership qualifier, tells compiler how to insert retain/release
calls. not needed when using 'assign'
copy
for objects. required when property is mutable. enables access to the property as it is when retrieved,
regardless of future changes.
34. Declared Property Directives
@property
●
declares an instance variable
@synthesize
●
●
●
compiler synthesizes getters and setters for you
default and optional
compiler will add this directive absent any other
@dynamic
●
●
●
you provide implementation of method dynamically
property itself is created dynamically at runtime
eg. subclasses of NSManagedObject
35. Logging
Logging is required for debugging… but
●
●
debug output should not be shipped, especially sensitive data
NSLog is slow
There are several options.
●
●
Define a macro. There are a variety of ways to do this.
○ Suppress NSLog in release mode altogether.
■ Gotcha: No error logs in production! And, it's still slow.
○ Introduce an alias for debug mode only, and allow NSLog for errors.
■ Gotcha: Warnings galore! And, it's still slow.
Roll your own logger
○
●
http://doing-it-wrong.mikeweller.com/2012/07/youre-doing-it-wrong-1-nslogdebug-ios.html
Integrate a library
○
○
○
https://github.com/CocoaLumberjack/CocoaLumberjack
https://github.com/fpillet/NSLogger : device doesn't need to be tethered
http://theonlylars.com/blog/2012/07/29/ditching-nslog-advanced-ios-logging-part-2/
36. Fast Enumeration
This is essentially 'for each' for Objective-C
Fast enumeration provides a performance advantage over index iteration.
// Using indexes
for (int i = 0; i < [thePeople count]; i++) {
Person *p = [thePeople objectAtIndex:i];
NSLog(@"%@ is %i years old.", [p name], [p age]);
}
// Using fast enumeration
for (Person *p in thePeople) {
NSLog(@"%@ is %i years old.", [p name], [p age]);
}
37. Key Value Coding and Observing
KVC: Any property can be accessed directly by a string, or string expression
KVO: Any object can subscribe to be notified about state change in any other object.
NSObject complies to NSKeyValueCoding protocol, so, KVO and KVC are widely available.
"Strngs" are error prone, instead use: NSStringValueForSelector(@selector(someProperty))
KVC enables KVO
●
●
●
subscribe
○ addObserver: forKeyPath:
respond
○ observeValueForKeyPath:
unsubscribe
○ removeObserver: forKeyPath:
○ requires proper bookkeeping, only try/catch as last resort
38. Blocks
When a block is created, it has read only access to local variables, unless
they are declared with "__block"
Blocks are closures.
A block
^{
NSString
*name
=
"Batman";
NSLog(@"My name is %@", name);
};
A block with an input parameter
^(int
value){
return
value*value;
}
A block variable
int (^square)
A local variable is shared
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
anInteger = 100;
};
testBlock();
//Integer is 42
NSLog(@"Value is now: %i", anInteger); //Value is now 100
(int)
=
^(int
return
};
int square_value = square(5);
value){
value*value;
Always utilize a weak reference to self
- (void)configureBlock {
MyClass * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture a weak reference to self
// to avoid a reference cycle
}
}
39. Multithreading
Threads
●
●
●
●
each thread has equal access to all app resources
any object can be modified, used, changed, by any thread
there is no way to predict how long a thread will run
there is no way to predict which thread will finish first
Thread Safety Threats
●
●
●
●
Race Conditions
○ if you read/write data concurrently from multiple threads, introduce a mutex lock by
wrapping instance vars in @synchronized(self){ object.iVar = value;}
Atomicity
Deadlock
○ a thread is blocked waiting for a condition that can never be met. this happens when two
threads executing with synchronized code call each other.
SleepyTime
○ too many threads executing at the same time bogs the system down
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
40. Grand Central Dispatch
GCD is a C API, so it looks different and is not Object-Oriented. The most basic usage of
GCD is to create a queue and then add one or more blocks to it.
-(void)fetchXML
{
dispatch_queue_t
This is a serial queue and blocks added to it are executed in order. If you always
dispatch blocks asynchronously, they will never deadlock.
fetchQueue
dispatch_queue_create(const
char
*label,
dispatch_queue_create("fetch
xml",
dispatch_async(fetchQueue,
NSString
dispatch_queue_t
=
NULL);
*URLString
NSURL
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block):
*URL
=
=
NULL);
^{
@"example.com/example.xml";
[NSURL
URLWithString:[URLString
stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
NSData
If there is code within the async block that must access the main UI thread, use:
NSXMLParser
*dataXML
=
=
[NSData
BOOL
[[NSXMLParser
dataWithContentsOfURL:URL];
alloc]
initWithData:dataXML];
[xmlParser
dispatch_async(dispatch_get_main_queue(), ^{....});
*xmlParser
setDelegate:self];
success
=
//
When a queued block is complete, you can use a completion block as a callback to
[xmlParser
test
if
perform post-execution functionality.
the
(success)
NSLog(@"No
}
For loops can be replaced/multi-threaded with dispatch_apply. Care must be taken to
else
parse];
result
{
errors");
{
NSLog(@"Error");
perform this optimization on it's own thread.
}
});
}
https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102
41. NSOperation
Built on top of GCD as of iOS 4
●
●
●
provides dependencies, priorities and completion blocks
can re-use, cancel and suspend operations
KVO compatible
Create custom operation objects
●
●
●
●
subclass NSOperation
override 'main'
create an autorelease pool in main
put your code within the autorelease pool
42. NSOperationQueue
A queue is not a thread
We provide queue with one or more operations
We can set maximum number of concurrent operations
The queue uses as many or few threads as it deems best
We can query the queue for which operations are left
We can pause the queue
We can cancel all operations in the queue
For simple operations, we can pass in a block rather than a subclass
43. Swizzling
The Objective-C runtime lets you modify the mappings from a selector (method name) to an implementation (the method code itself). This
allows you to "patch" methods in code you don't have the source to (AppKit, FoundationKit, etc).
Unlike creating a category method with the same name as the original method (effectively replacing the original method), MethodSwizzling lets
your replacement method make use of the original method, almost like subclassing or per-method posing.
This is best used in cases where a single method needs substitution or extension, as in adding a log for debugging; If you need to modify many
behaviours of a class, you may be better off using Class Posing.
http://darkdust.net/writings/objective-c/method-swizzling
●
create a category on the object that has the method you want to swizzle
●
implement your wrapper method - this will execute your new stuff and call itself to call the original code, like a subclass override
●
implement +(void) load and exchange implementations
●
when original method selector is called, your new implementation will be run
●
when your implementation calls itself, it will actually be calling the original implementation because they have been exchanged!
44. Posing
Little used and deprecated in Objective-C 2.0 (OS X v10.5)
Unavailable in 64-bit runtime
Replacement is per-method swizzling.
Entirely replace one class with another, globally
●
●
●
●
●
Posing class may only pose for one of its superclasses.
Posing class may not introduce new instance variables.
Posing class can call overridden methods through super()
Posing class can override methods defined in categories.
Posing must be done before any calls are made to the class.
○ typically in header of Posing Class
○ class_poseAs ([CustomNSApplication class], [NSApplication class]);
45. Categories
Add methods to a class without making a subclass.
Methods become part of the class type and are inherited by its subclasses.
Can not add new instance variables
Can override existing methods, but not recommended
Used to declare informal protocols
47. Forwarding
Objects are given the opportunity to forward messages that they do not handle.
Some say this deep magic is best avoided and the problem it solves should be
solved another way, so look for one.
Any NSObject can implement the forwardInvocation method.
●
●
provide a target
pass the message to the new target along with parameters
49. Design Pattern: MVC
●
●
●
Model
○ application data
○ NSObject
○ notifies Controller of data changes
View
○ display object
○ UIView
○ notifies Controller of user input
Controller
○ business logic
○ UIViewController
○ updates the Model and the View
http://www.raywenderlich.com/46988/ios-design-patterns
50. Design Pattern: Singleton
Singleton
Ensure a single instance of a class
Provide a global access point
●
●
widely used by Apple
value in application code is debated by community
○ interferes with testing
■ when a class uses a Singleton, there's no way to mock it
○ unnecessary, and desired results can be achieved in other ways
■ simply don't instantiate more than one
■ use dependency injection to pass objects in
■ use a Facade in the AppDelegate
○
http://stackoverflow.com/questions/5912541/alternative-to-singleton-in-objective-c-for-better-application-design
51. Design Pattern: Abstract Factory
Provides an interface for creating related or dependant objects without
specifying concrete implementations.
Client is decoupled from concrete object obtained from the factory.
Common iOS implementation is Class Clusters
●
●
●
●
Foundation makes extensive use
Class Clusters group a number of private concrete subclasses
implemented under a public abstract superclass
superclass must declare methods to create instances of private classes
52. Design Pattern: Facade
Facade
Interface to simplify one or more subsystems.
A good alternative to Singleton.
Common iOS implementation can be done with Class Clusters
●
●
eg. a call to facade.save(data) can store data locally and also over network (if
available), using whatever classes, instances, frameworks it needs to.
encapsulate framework, class, method, and hardware checks, making it easy
to maintain, extend and deprecate support
53. Design Pattern: Strategy
Strategy
Easily switch out different algorithmic implementations in different situations.
Encourages composition, is a good alternative to inheritance.
An object with an expected behavior is provided a variation of it.
Common iOS implementation is done with protocols.
●
●
●
●
define a protocol with a required 'execute' method
define hierarchy of related behavior/strategy objects conforming to protocol
define hierarchy of client objects which have desired behavior
compose the clients with appropriate strategies, as needed
54. Design Pattern: Decorator
Decorator
Encourages composition, a good alternative to inheritance.
Easily swap and add behavior without modifying class.
Similar benefits as Strategy, but enables adding new behaviors.
Common iOS implementations are Categories and Delegation
●
●
Categories
○ add extra methods to an existing class at compile time.
○ @interface NSArray(Extras)
○ can be used to outright replace existing methods
Delegation
○ a delegate acts on behalf of another by conforming to a protocol
○ only one object can be a delegate at a time, but can be changed dynamically
55. Design Pattern: Adapter
Allows classes with incompatible interfaces to work together.
Converts the interface of a class to one clients expect/require.
Common iOS implementation is done with protocols.
●
●
●
●
a protocol is a language feature that makes it possible to define interfaces
a protocol's interface is not associated with any particular class
informal protocol
○ declared as a category on NSObject, and can be adopted by any object
○ all methods are implicitly optional
○ conforming object must re-declare methods in it's interface
○ no runtime support: can't type check or introspect
formal protocols
○ declared with @protocol directive
○ implicitly requires conforming class to implement all declared methods
○ methods can be marked optional
○ have runtime support: type checking, introspection
56. Design Pattern: Composite
Composes related objects into tree structures to represent part-whole
hierarchies.
Allows clients to treat individual objects and compositions of objects uniformly.
Used to achieve MVC
57. Design Pattern: Observer
Defines a one-to-many dependency between one observable object and many
observers where observers are decoupled from the observable.
Observers want to know about changes in the observable object.
Common iOS implementations are
●
●
●
●
NSNotifications
KVO
Delegation (one-to-one)
NSOperation completion block
58. Design Pattern: Memento
Captures and externalizes state for later restoration
Common iOS implementations include
●
●
●
●
●
NSUserDefaults to store and retrieve simple data
Archiving model objects with NSCoding protocol
plist serialization of dictionary, array, string, data, date and number
Core Data for complex model object persistence
UI state preservation and restoration API introduced in iOS 6
59. Design Pattern: Command
Encapsulate requests.
Decouples objects that send messages from objects that receive them.
Encapsulated requests can be stored, played back, queued, modified
Common iOS implementation
●
●
target-action mechanism
○ control object maps target-action to touch event
○ control sends action message to target controller
NSInvocation used for undo operations
○ has a target, a selector and some parameters
○ can be changed dynamically and executed as needed
○ can persist a request or chain of requests
60. Design Pattern: Chain of
Responsibility
Decouples sender of request from receiver by giving more than one object a
chance to handle the request.
When you construct a UI, you get a responder chain for free.
UIView hierarchy contains a responder chain.
You can inject custom responders and manipulate the order.
61. Design Pattern: Template
Defines the skeleton and structure of an algorithm.
Subclasses refine and complete the algorithm without changing the structure.
Usage is prevalent in framework development.
User subclasses framework class, overrides template methods and and adds
app specific functionality.
62. Design Pattern: Iterator
A way to sequentially access elements of a collection.
Transfer traversal from collection to iterator.
Common iOS implementation
●
NSEnumerator can traverse arrays, sets, dictionaries
63. Design Pattern: Mediator
Encapsulate how a set of objects interact, decoupling them from each other.
Mediated objects tell the mediator when their state changes and also respond
to mediator requests.
Common iOS implementation
●
ViewControllers