23. Data
struct FeedCellModel {
let name: String
let description: String
let image: URL?
}
Lagano za verificirati,
bez stanja (nepromjenljivo)
24. class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
25. class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
26. class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
27. class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
28. class FeedViewModel {
func loadData() {
self.state = .loading
feedService.getFeedItem(page: 0) { result in
switch result {
case let .success(items):
if items.isEmpty {
self.state = .noData
} else {
let models = self.feedCellModels(from: items)
self.state = .loaded(models)
}
case let .failure(error):
let errorText = self.errorText(for: error)
self.state = .error(errorText)
}
}
}
}
29. class FeedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
viewModel.onStateChanged = { [weak self] state in
guard let `self` = self else { return }
switch state {
case .noData:
self.refreshControl.endRefreshing()
self.manager.data = []
self.errorImage.isHidden = true
self.errorLabel.text = Localizable.error_empty_feed
self.errorView.isHidden = false
case .error(let error):
self.manager.data = []
self.refreshControl.endRefreshing()
self.errorImage.isHidden = false
self.errorLabel.text = error
self.errorView.isHidden = false
case .loaded(let items):
self.refreshControl.endRefreshing()
self.manager.data = items
self.errorView.isHidden = true
case .loading:
self.refreshControl.beginRefreshing()
}
}
}
30. Prednosti
1. Cijeli state na jednom mjestu
2. Manipulacija statea izdvojena iz iOS-a
3. Lagano ubacivanje dodatnog
statea
85. Testing For People Who Hate Testing
https://eev.ee/blog/2016/08/22/testing-for-people-who-hate-testing/
AutoMockable Sourcery template
https://cdn.rawgit.com/krzysztofzablocki/Sourcery/master/docs/mocks.html
Unit Testing in Swift
https://medium.cobeisfresh.com/unit-testing-in-swift-part-1-the-philosophy-9bc85ed5001b