데이터와 관련해서 코드를 짤 때, 배열과 함께 딕셔너리도 많이 사용한다. 현재 진행하고 있는 프로젝트에서도 딕셔너리를 사용해서 이미지를 저장하고 불러오는 작업을 진행하고 있었다.
var selectedImage: [String: UIImage] = [:]
이렇게 딕셔너리 타입의 변수를 선언했다. 그 다음,
// 딕셔너리에 추가하는 코드 작성
let index = firebaseManager.selectedImage.count
firebaseManager.selectedImage[String(index)] = image
// 업데이트된 이미지 배열로 컬렉션 뷰를 새로고침
createNoticeBoardView.galleryCollectionView.reloadData()
갤러리에서 선택한 사진을, index 값을 추가시키면서 해당 딕셔너리에 추가하는 방법으로 진행을 했었다. 그런데 문제가 발생했었다.
사진을 여러개 추가한 후, 중간의 사진을 삭제하면, 뒤에 있는 사진들이 cell에 보이지 않음
예를 들어 사진을 3개를 추가한 상태라고 해보자. 그렇다면 "0": asdf
, "1": qwer
, "2": zxcv
이런 식으로 딕셔너리에 저장이 되어 있을 것이다. 그런데 중간 사진인 "1": qwer
을 삭제하게 되면 "0": asdf
, "2": zxcv
만 남게 되고, cell은 index가 0
, 1
이 된다. 즉, 딕셔너리와 cell의 순서가 맞지 않게 되는 것이다.
그렇다면 사진이 삭제되고 난 후에, 딕셔너리를 다시 재정렬 시키면 될것이다.
사진을 삭제하면, CollectionView를 업데이트하고, cell이 삭제되는 모습을 사용자에게 자연스럽게 보여주고, 효율적으로 업데이트 하기 위해 performBatchUpdates(_:completion:)
를 사용하자.
performBatchUpdates(_:completion:)
의 사용방법은 다음과 같다.
collectionView.performBatchUpdates({
// 이 블록 내에서 컬렉션 뷰의 변경 사항을 배치
// 예를 들어, 아이템 추가, 삭제, 섹션의 삽입, 삭제 등을 실행
collectionView.insertItems(at: [IndexPath])
collectionView.deleteItems(at: [IndexPath])
collectionView.reloadItems(at: [IndexPath])
// 등등...
}, completion: { finished in
// 변경 사항을 적용한 후에 실행할 작업을 여기에 작성
// 'finished' 파라미터는 애니메이션이 완료되었는지 여부를 나타냄
if finished {
// 애니메이션이 완료된 후 실행할 코드
}
})
프로젝트에 적용하면 다음과 같다.
self.createNoticeBoardView.galleryCollectionView.performBatchUpdates {
} completion: { _ in
}
이제 컬렉션 뷰의 변경 사항을 배치하자. 선택된 index에 해당하는 이미지를 딕셔너리에서 삭제하고, 해당 아이템을 CollectionView에서 삭제한다.
self.createNoticeBoardView.galleryCollectionView.performBatchUpdates {
// 선택된 인덱스에 해당하는 이미지를 딕셔너리에서 삭제
self.firebaseManager.selectedImage[String(indexPath.row)] = nil
// 해당하는 아이템을 CollectionView에서 삭제
self.createNoticeBoardView.galleryCollectionView.deleteItems(at: [indexPath])
} completion: { _ in
}
이제 딕셔너리의 키를 재정렬 해주자.
// 딕셔너리의 키를 재정렬
var newSelectedImage: [String: UIImage] = [:]
let sortedKeys = self.firebaseManager.selectedImage.keys.compactMap { Int($0) }.sorted()
// 재정렬할 때 사용할 새 인덱스
var newIndex = 0
for key in sortedKeys {
if let image = self.firebaseManager.selectedImage[String(key)] {
newSelectedImage[String(newIndex)] = image
newIndex += 1
}
}
우선 재정렬하기 위한 새로운 딕셔너리를 만든다. 그 다음 기존 딕셔너리의 키를 가져와서 compactMap
을 사용하여 각 키를 Int로 변환하고, 변환에 성공한 키만 sorted()
를 통해 오름차순으로 정렬한다.
재정렬을 위한 새로운 인덱스도 만들어준다. 정렬된 키 sortedKeys
를 순회하면서 각 키에 해당하는 이미지를 원본 딕셔너리 self.firebaseManager.selectedImage
에서 찾아 새로운 딕셔너리 newSelectedImage
로 옮긴다. 여기서는 원본 딕셔너리의 키(String(key))
를 사용하여 값을 가져온다.
그 다음 옵셔널 바인딩을 사용하여 self.firebaseManager.selectedImage[String(key)]
에서 UIImage를 성공적으로 얻어내면 그 이미지를 newSelectedImage
에 String(newIndex)
를 키로 사용하여 삽입합니다.
마지막으로 새로운 딕셔너리에 항목을 추가할 때마다 newIndex를 1씩 증가시켜, 새로운 키가 연속적이고 오름차순이 되도록 한다.
func removeLocal(_ indexPath: IndexPath) {
// 로컬에서 이미지를 삭제하고 Collection View를 업데이트
self.createNoticeBoardView.galleryCollectionView.performBatchUpdates {
// 선택된 인덱스에 해당하는 이미지를 딕셔너리에서 삭제
self.firebaseManager.selectedImage[String(indexPath.row)] = nil
// 해당하는 아이템을 CollectionView에서 삭제
self.createNoticeBoardView.galleryCollectionView.deleteItems(at: [indexPath])
} completion: { _ in
// 딕셔너리의 키를 재정렬
var newSelectedImage: [String: UIImage] = [:]
let sortedKeys = self.firebaseManager.selectedImage.keys.compactMap { Int($0) }.sorted()
// 재정렬할 때 사용할 새 인덱스
var newIndex = 0
for key in sortedKeys {
if let image = self.firebaseManager.selectedImage[String(key)] {
newSelectedImage[String(newIndex)] = image
newIndex += 1
}
}
// 재정렬된 이미지 딕셔너리를 업데이트
self.firebaseManager.selectedImage = newSelectedImage
// self.createNoticeBoardView.galleryCollectionView.reloadData()
}
}