AnyModelStore의 필요성
- 접근 문제 → 데이터 Collection 아이템 접근을 first로 한다. (순회 발생)
var musicRegistration: UICollectionView.CellRegistration<UICollectionViewListCell,Item>{
UICollectionView.CellRegistration { cell, indexPath, itemIdentifier in
guard itemIdentifier.itemType == .music,
let data:MusicItem = self.musicItems.first(where: {$0.id == itemIdentifier.id}) else {return}
}
}
- 업데이트 문제 → 데이터 Collection 아이템을 인덱스로 접근한다. (순회 발생)
💡 배열 값을 업데이트 하기 위해선 인덱스 접근을 해야하는 것이 가장 큰 문제이다
func toggleShortVideo(item:Item){
guard var dataIdx = self.shortVideoItems.firstIndex(where:{item.id == $0.id}) else {return}
shortVideoItems[dataIdx].isLike.toggle()
}
AnyModelStore
Building High-Performance Lists and Collection Views | Apple Developer Documentation
Improve the performance of lists and collections in your app with prefetching and image preparation.
developer.apple.com
이 예제 코드를 이용함!! → 좀 더 단순화한 코드
import Foundation
import Combine
protocol ModelStoreAble {
associatedtype Model: Identifiable
func fetchByID(_ id: Model.ID) -> Model!
}
class AnyModelStore<Model: Identifiable>: ModelStoreAble {
private var models = [Model.ID: Model]()
init(_ models: [Model]) {
// 모델의 배열을 [모델 아이디 : 모델] 형식의 Dictionary로 바꿔준다.
// => 고유한 값에 고유한 데이터만 존재
self.models = models.groupingByUniqueID()
}
// 모델의 id를 통해서 저장소에서 Model을 가져온다
func fetchByID(_ id: Model.ID) -> Model! {
return self.models[id]
}
func insertModel(item: Model){
models[item.id] = item
}
func removeModel(_ id:Model.ID){
models.removeValue(forKey: id)
}
}
// 배열 익스텐션 -> 원소들이 Identifiable을 준수하는 것들에 적용되는 함수
extension Sequence where Element: Identifiable {
func groupingByID() -> [Element.ID: [Element]] {
return Dictionary(grouping: self, by: { $0.id })
}
func groupingByUniqueID() -> [Element.ID: Element] {
return Dictionary(uniqueKeysWithValues: self.map { ($0.id, $0) })
}
}
AnyModelStore를 이용해서 개선한 위 문제점
- 접근 문제: O(1)의 시간 복잡도로 접근 가능
var musicRegistration: UICollectionView.CellRegistration<UICollectionViewListCell,Item>{
UICollectionView.CellRegistration { cell, indexPath, itemIdentifier in
guard itemIdentifier.itemType == .music,
let data: MusicItem = self.musicStore.fetchByID(itemIdentifier.id) else {return}
}
}
- 업데이트 문제: O(1)의 시간 복잡도로 접근 가능
func toggleShortVideo(item:Item){
guard var data = self.shortVideoStore.fetchByID(item.id) else {return}
data.isLike.toggle()
self.shortVideoStore.insertModel(item: data)
}
전체 개선 코드
struct MusicItem:Identifiable,Hashable{
var id = UUID()
var artist = "Newjeans"
}
struct ShortVideo:Identifiable,Hashable{
var id = UUID()
var isLike = false
var tictoker = "Leo"
}
struct VideoItem:Identifiable,Hashable{
var id = UUID()
var youtuber = "calmdownman"
}
final class TempVC: UIViewController{
enum MediaType{
case video
case music
case shortVideo
}
struct Item:Identifiable,Hashable{
var id:UUID
var itemType: MediaType
}
var videoStore:AnyModelStore<VideoItem>!
var shortVideoStore:AnyModelStore<ShortVideo>!
var musicStore: AnyModelStore<MusicItem>!
var dataSource: UICollectionViewDiffableDataSource<MediaType,Item>!
override func viewDidLoad() {
super.viewDidLoad()
var snapshot = NSDiffableDataSourceSnapshot<MediaType,Item>()
var videoItems = (0...20).map{_ in VideoItem()}
var shortVideoItems = (0...40).map{_ in ShortVideo()}
var musicItems = (0...60).map{_ in MusicItem()}
videoStore = .init(videoItems)
shortVideoStore = .init(shortVideoItems)
musicStore = .init(musicItems)
snapshot.appendSections([.video,.music,.shortVideo])
snapshot.appendItems(videoItems.map{Item(id: $0.id, itemType: .video)},toSection: .video)
snapshot.appendItems(musicItems.map{Item(id: $0.id, itemType: .music)},toSection: .music)
snapshot.appendItems(shortVideoItems.map{Item(id: $0.id, itemType: .music)},toSection: .shortVideo)
dataSource.apply(snapshot,animatingDifferences: true)
}
var musicRegistration: UICollectionView.CellRegistration<UICollectionViewListCell,Item>{
UICollectionView.CellRegistration { cell, indexPath, itemIdentifier in
guard itemIdentifier.itemType == .music,
let data: MusicItem = self.musicStore.fetchByID(itemIdentifier.id) else {return}
}
}
func toggleShortVideo(item:Item){
guard var data = self.shortVideoStore.fetchByID(item.id) else {return}
data.isLike.toggle()
self.shortVideoStore.insertModel(item: data)
}
}'이모저모 > UIKit' 카테고리의 다른 글
| UIButton State 애니메이션용 모듈 만들고 적용하기 (0) | 2023.11.25 |
|---|---|
| CustomDiffableDataSource와 MVVM으로 Cell 데이터 관리하기 #0 (0) | 2023.11.18 |
| 다양한 셀을 그리는 DiffableDataSource 데이터 구성하기 #1 (0) | 2023.11.10 |
| 애플 앱 프로필 버튼 만들기 (0) | 2023.09.15 |
| Modern UIKit Collection, TableView #2-3 (0) | 2023.09.03 |
댓글