5. GOALS OF SOFTWARE
ARCHITECTURE
Code is comprehensible for other developers
Code can adopt to changing requirements
Code can be shared within the project and throughout
multiple projects
10. SINGLE RESPONSIBILITY PRINCIPLE
Avoid having many responsibilities within a single class
Very important when implementing UIViewController
subclasses
Bad View Controller handles: Persistence, Business
Logic, View Logic, etc.
12. ENCAPSULATE
Every component should know as little as possible
about its surrounding components
→ reduces dependencies between components
How can this be accomplished?
→ small interfaces for communication
13. ENCAPSULATE
Add Trip View Controller Core Data Client
startSavingNewTrip(newTrip)
displayError(nameError)
setNameOfTrip(“SF Trip”)
disableSaveButton()
Classes are poorly encapsulated and very dependent on
each other - very hard to change code in any of the two classes
14. ENCAPSULATE
Add Trip View Controller Core Data Client
saveTrip(newTrip)
saveErrorOccurred(error)
Small communication interface
reduces dependencies!
17. AVOID THE MASSIVE VIEW
CONTROLLER
Rule of thumb: A View Controller with > 300 lines is
probably doing more than it should do
18. THINGS A VIEW CONTROLLER
SHOULD DO
Listen to callbacks from the View → invoke methods on
the model layer → send responses from model back to
the view
19. THINGS A VIEW CONTROLLER
SHOULD NOT DO
Construct complex network requests
Construct complex database queries
Take care of object serialization / deserialization
21. DEFINE EXPRESSIVE APIS
E.g. instead of exposing details of the network layer,
provide functions with a simple interface:
func fetchAllUsers(callback: [User] -> ())
fetchAllUsers { users in
print(users)
}
23. USE VIEW OBJECTS
View objects encapsulate multiple properties that are
relevant for a type to be displayed by a custom view
This is preferred over setting individual properties from
outside the view
24. USE VIEW OBJECTS
class UserView: UIView {
@IBOutlet var nameLabel: UILabel!
@IBOutlet var profilePictureImageView: UIImageView!
var user: User? {
didSet {
nameLabel.text = user?.name
profilePictureImageView.image = user?.profilePicture
}
}
}
let userView = UserView()
let currentUser = User()
currentUser.name = "TestUser"
userView.user = currentUser
View encapsulates how an
object is displayed!
25. USE VIEW OBJECTS
class UserView: UIView {
@IBOutlet var nameLabel: UILabel!
@IBOutlet var profilePictureImageView: UIImageView!
}
let userView = UserView()
let currentUser = User()
currentUser.name = "TestUser"
userView.nameLabel.text = currentUser.name
userView.profilePictureImageView.image = currentUser.profilePicture
Code that uses UserView now
depends on its UI components.
Violates encapsulation!
27. BE WARY OF INHERITANCE
Base View
Class
Trip View
You can only inherit one set of functionality
You tend to inherit functionality that you don’t need
More modular alternatives:
Functions that can operate on relevant types
(using generics)
Protocols & Protocol Extensions
28. BE WARY OF INHERITANCE
Base View
Class
Trip View
More Specific
Trip View
Trip View
Error
Representable
Restorable Presentable
30. SUMMARY
Divide code into logical domains
Strive for each unit of code having a single responsibility
Consider using protocols instead of inheritance
Define narrow and expressive APIs that hide
implementation details of other units of code and
reduce dependencies between your units