ViewModel 객체 분리
뷰에서 표현해야할 데이터를 네트워킹을 통해 외부에서 가져와야할 때 ViewModel
객체로 분리시켜서 데이터를 업데이트 했습니다. 네트워킹을 통해 데이터를 가져와야 하는 뷰가 많아서 각 뷰모델이 겹치는 경우가 많아서 전체적으로 사용할 기본 뷰모델 MiniVibeViewModel
을 만들었습니다.
class MiniVibeViewModel: ObservableObject {
private let network = NetworkService(session: URLSession.shared)
private var cancellabes = Set<AnyCancellable>()
func internalFetch(endPoint: MiniVibeType, id: Int? = nil, filterQuery: String? = nil, limitQuery: String? = nil, completion: @escaping (Data) -> Void) {
let url = URLBuilder(pathType: .api, endPoint: endPoint, id: id, filterQuery: nil, limitQuery: nil).create()
guard let request = RequestBuilder(url: url,
body: nil,
headers: nil).create() else { return }
network.request(request: request)
.sink { result in
switch result {
case .failure(let error):
print(error)
case .finished:
print("success")
}
} receiveValue: { data in
completion(data)
}
.store(in: &cancellabes)
}
}
각 뷰모델마다 다른 부분은 네트워킹을 통해 받아온 데이터를 처리하는 부분입니다. 따라서 그 부분만 클로저로 분리시켜서 넘겨주는 방식으로 작성하였습니다.
그 다음 구체적인 뷰모델을 작성할 때 앞서 작성한 MiniVibeViewModel
을 상속받았습니다.
class ThumbnailListViewModel: MiniVibeViewModel {
@Published var thumbnails = [Thumbnailable]()
private let network = NetworkService(session: URLSession.shared)
private var cancellabes = Set<AnyCancellable>()
func fetch(type: MiniVibeType, id: Int) {
internalFetch(endPoint: type, id: id) { [weak self] data in
switch type {
case .magazines:
if let decodedData = try? JSONDecoder().decode(Magazines.self, from: data) {
DispatchQueue.main.async {
self?.thumbnails = decodedData.magazines
}
}
default:
if let decodedData = try? JSONDecoder().decode(Playlists.self, from: data) {
DispatchQueue.main.async {
self?.thumbnails = decodedData.playlists
}
}
}
}
}
}
에러 발생
이때 문제가 발생하였습니다. 뷰모델을 분리시켜서 상속받기 전에는 잘 동작하던 뷰 업데이트가 동작하지 않았습니다.🤦♀️
디버깅을 해보니 네트워킹을 통해 데이터를 잘 받아오지만 업데이트 되었다는 것을 뷰에게 알리지 못하는 것 같았습니다.(추측)🧐
뷰가 onAppear
할 때 제대로 데이터가 업데이트 되었다면 해당 데이터를 출력하기 위한 부분이 동작해야하는데 이 부분이 동작되지 않는 것을 볼 수 있습니다.
해결
혹시나 해서 부모 뷰모델에서 ObservableObject
프로토콜을 제외하고 각 뷰모델마다 따로 상속받도록 하였습니다.
class MiniVibeViewModel {
...
class ThumbnailListViewModel: MiniVibeViewModel, ObservableObject {
@Published var thumbnails = [Thumbnailable]()
...
이렇게 했더니 제대로 동작합니다. 👀
왜인지는 모르겠습니다.
원인 분석
1. 부모객체가 상속받은 프로토콜은 상속이 안된다.
그랬으면 애초에 각 뷰모델에 @Published
를 포함하고 있어서 ObservableObject
을 따로 상속받지 않으면 오류가 발생했어야 합니다.
2. @Published 프로퍼티가 변화했을 때 이를 사용하는 부분에 알려주는 기능만 상속이 안된다.
적어놓고도 이해가 안가네요. 부분적인 기능만 상속되기도 하나요? 🤭
3. 그냥 Xcode가 고장났다.
왠지모르게 가장 이해가 되...읍..
'iOS > SwiftUI' 카테고리의 다른 글
SwiftUI) NavigationLink와 Memory Leak (2) | 2020.12.05 |
---|---|
SwiftUI) URL로 비동기 이미지 생성하기 - Combine과 Network (0) | 2020.12.05 |
SwiftUI) ViewBuilder 와 guard let (1) | 2020.12.03 |
SwiftUI) MVVM과 Combine (0) | 2020.11.24 |
SwiftUI) 다이나믹 리스트 (0) | 2020.11.22 |