8. struct Contact {
let firstName: String
let lastName: String
let email: String
let cellPhone: String?
let phone: String?
let birthdate: Date
let bloodType: BloodType
let hairColor: Color
let eyeColor: Color
let height: Int
let weight: Int
let nickname: String?
let spouse: Contact?
}
27. private var listIsEmpty: Bool
private var currentRequest: Request?
private var loadError: Error?
private var isLoading: Bool {
return currentRequest != nil
}
28. enum ViewState {
case willLoadInitialData
case loaded(repos:[String])
case loading(Request, oldRepos:[String])
case loadedWithError(repos:[String], Error)
case empty
}
33. enum ViewState {
case willLoadInitialData
case loaded(repos:[String], selected: String?)
case loading(Request, oldRepos:[String], selected: String?)
case loadedWithError(repos:[String], Error, selected: String?)
case empty
}
37. enum ViewState {
case willLoadInitialData
case offline(repos:[String], changes: [Change], selected: String?)
case loaded(repos:[String], selected: String?)
case loading(Request, oldRepos:[String], selected: String?)
case loadedWithError(repos:[String], Error, selected: String?)
case empty
}
40. class State<Type> {
let key: String
var value: Type {
return __value
}
private var __value: Type
init(_ defaultValue: Type, key: String) {
self.__value = defaultValue
self.key = key
}
public func modify(_ value: Type) {
__value = value
didModify()
}
func didModify() {
}
}
41. protocol StateListener : AnyObject {
func stateModified<T>(_ state: State<T>)
}
protocol OptionalType {
var isNil: Bool { get }
}
extension Optional : OptionalType {
public var isNil: Bool {
return self == nil
}
}
42. class MonitoredState<Type> : State<Type> {
fileprivate let listeners: NSHashTable<AnyObject>
override init(_ defaultValue: Type, key: String) {
self.listeners = NSHashTable<AnyObject>.weakObjects()
super.init(defaultValue, key: key)
}
var allListeners: [StateListener] {
return self.listeners.allObjects.map({ $0 as? StateListener }).flatMap({ $0 })
}
override func didModify() {
super.didModify()
let allListeners = self.allListeners
let state = self
for l in allListeners {
l.stateModified(state)
}
}
func attach(listener: StateListener) {
self.listeners.add(listener as AnyObject)
}
}
43. class UserDefaultsState<Type> : MonitoredState<Type>, StateListener {
let innerState: MonitoredState<Type>
init(state: MonitoredState<Type>) {
self.innerState = state
super.init(state.value, key: state.key)
let existingValue = UserDefaults.standard.object(forKey: key)
if let existing = existingValue as? Type {
state.modify(existing)
} else if let data = existingValue as? Data, let decoded = NSKeyedUnarchiver.unarchiveObject(with: data) as? Type {
state.modify(decoded)
}
if let monitoredState = state as? MonitoredState<Type> {
monitoredState.attach(listener: self)
}
}
override var value: Type {
return innerState.value
}
override func modify(_ value: Type) {
innerState.modify(value)
}
func stateModified<T>(_ state: State<T>) {
self.didModify()
}
override func didModify() {
super.didModify()
let val = self.value
if let val = val as? OptionalType, val.isNil {
UserDefaults.standard.removeObject(forKey: self.key)
print("Removed (self.key) from UserDefaults")
} else if let val = val as? NSCoding {
UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: val), forKey: self.key)
print("Saved (self.key) to UserDefaults")
} else {
UserDefaults.standard.set(val, forKey: self.key)
print("Saved (self.key) to UserDefaults")
}
UserDefaults.standard.synchronize()
}
}
44. class HistoryState<Type>: MonitoredState<Type>, StateListener {
let innerState: MonitoredState<Type>
private var __history: [Type] = []
public var history: [Type] {
return __history
}
override var value: Type {
return innerState.value
}
override func modify(_ value: Type) {
innerState.modify(value)
}
func stateModified<T>(_ state: State<T>) {
self.didModify()
}
init(state: MonitoredState<Type>) {
self.innerState = state
super.init(state.value, key: state.key)
if let monitoredState = state as? MonitoredState<Type> {
monitoredState.attach(listener: self)
}
}
override func didModify() {
super.didModify()
__history.append(self.value)
}
}