Software-Architektur/-Design in der iOS-Entwicklung. In der traditionellen iOS-Entwicklung mit MVC (Model View Controller) oder heutzutage “trendigem” MVVM (Model View ViewModel) wird wenig bis keine Rücksicht auf den State (bzw. die Daten) in der App genommen. Das führt oft zu schwer verständlichem, und schlecht wartbarem Code, da alles undefiniert und quer verstreut in der App gemacht wird. Daher ist es essentiell, sich um die Organisation des States in der App zu kümmern. Um das Rad nicht neu zu erfinden, bedienen wir uns an Frameworks/Libraries wie ReSwift*, RxSwift** und die Verbindung der beiden “Technologien” über ReRxSwift***. Diese bieten ein gutes State-Management, was dazu führt, dass der State nur an einer Stelle in der App (im s.g. Store) verwaltet wird und nur kontrolliert (über s.g. Actions/Reducers) verändert werden kann. Über s.g. Subscriptions kann man den aktuellen Stand und Änderungen des States erfahren (z.B. in ViewControllers oder Views).
* Swift Implementierung von Redux (JavaScript)
** Swift Implementierung von reactiveX (für quasi jede populäre Programmiersprache verfügbar)
*** Swift Implementierung von react-redux (JavaScript)
25. // define the store
let store = Store<State>(reducer: reducer, state: nil)
// define a state (important: value type)
struct State: StateType {
var data: String = "someData"
}
27. // define an action
struct ChangeData: Action {
let changedData: String
}
// create and dispatch an action
let action = ChangeData(changedData: "changedData")
store.dispatch(action)
29. // reducer: action + state = new state
func reducer(action: Action, state: State?) -> State {
}
*switch is non-exhausting for simplicity
// create a new state if state is nil
var state = state ?? State()
// switch through desired actions
switch action {
case let action as ChangeData:
}
// perform state change
state.data = action.changedData
// return the new state
return state
31. class ReSwiftViewController: UIViewController, StoreSubscriber {
@IBOutlet weak var button: UIButton!
@IBOutlet weak var label: UILabel!
}
// subscribe to store
func setup() {
store.subscribe(self)
}
// receive state updates from store
func newState(state: State) {
self.label.text = state.data
}
// dispatch an action to store
@IBAction func buttonTap(_ sender: Any) {
let action = ChangeData(changedData: "changedData")
store.dispatch(action)
}
41. // define data as a subject ("stream")
let data = PublishSubject<String>()
// subscribe to data
data.asObservable()
.subscribe(onNext: { string in
print("data changed to: (string)")
})
// bind data to label
data.bind(to: label.rx.text)
*disposing is left out for simplicity
// trigger an update
data.onNext("changedData")
58. class ReRxSwiftViewController: UIViewController {
@IBOutlet weak var button: UIButton!
@IBOutlet weak var label: UILabel!
}
// set up connection with store and mappings
let connection = Connection(store: store,
mapStateToProps: mapStateToProps,
mapDispatchToActions: mapDispatchToActions)
// establish connection and bind to a label
func setup() {
self.connection.connect()
self.connection.bind(Props.data, to: self.label.rx.text)
}
// dispatch an action
@IBAction func buttonTap(_ sender: Any) {
self.connection.actions.changeData("changedData")
}