UICollectionView에 대해서 알아보기 5편 (북마크 구현 및 모델 관리)
이번에는 bookmark 기능을 구현해 볼 예정이다.
이전에도 북마크를 구현했었고, 모델을 잘 만들어서 관리하고 있었다.
그러니까 기록용의 의미가 더 큼!
UI
우선 모델을 변경했다.
서버에서 내려오는 데이터는 id, name, avatar, job, age뿐이지만, isBookmark를 추가해서 북마크 여부를 나타내는 프로퍼티를 만들었다.
Equtable을 채택해서 멤버의 구조체의 5가지 정보가 다 같으면 같은 객체로 판단하게 했다.
여기 MemberAPI가 Member에 해당하는 조합을 일정하게 주는게 아니라, id, name, avatar, job, age를 랜덤하게 조합해서 주는것 같았다.
id는 고유값이 아니라 배열의 index 정보라서 늘 업데이트 되어서 결국은 같은 객체를 얻는게 불가능해서 이는 리액터킷을 적용할 때, 다른 예제를 갖고오도록 하겠다.
//
// RestaurantList.swift
// AppleCollectionView
//
// Created by Hamlit Jason on 2022/08/23.
//
import UIKit
struct Member: Codable, Hashable, Equatable {
let id: Int
let name: String
let avatar: String
let job: String
let age: Int
var isBookmark: Bool {
isBookmark(member: Member(id: id, name: name, avatar: avatar, job: job, age: age))
}
/// 아이디 값이 같으면 같은 객체로 판정
static func ==(lhs: Member, rhs: Member) -> Bool {
return lhs.id == rhs.id &&
lhs.name == rhs.name &&
lhs.avatar == rhs.avatar &&
lhs.job == rhs.job &&
lhs.age == rhs.age
}
}
extension Member {
fileprivate func isBookmark(member: Member) -> Bool {
UserDefaultManager.bookmark.contains(member)
? true
: false
}
}
셀은 아래처럼 구성했다.
configureCell(with: Member)에서 Member 객체를 받아서 프로퍼티로 따로 저장하고 있다.
이 정보를 이용해 bookmark를 관리!
//
// MemberCell.swift
// AppleCollectionView
//
// Created by Hamlit Jason on 2022/08/23.
//
import UIKit
import SnapKit
import Nuke
import RxSwift
import RxCocoa
class MemberCell: UICollectionViewCell {
let disposeBag = DisposeBag()
var avatarImage = UIImageView()
var nameLabel = UILabel()
var jobLabel = UILabel()
var bookmarkButton = UIButton()
var member: Member?
override init(frame: CGRect) {
super.init(frame: .zero)
setupAvatarImage()
setupNameLabel()
setupJobLabel()
setupBookmarkButton()
bind()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/// 셀 세팅
func configureCell(with item: Member) {
member = item
if let url = URL(string: item.avatar) {
let options = ImageLoadingOptions(failureImageTransition: .fadeIn(duration: 0.5))
Nuke.loadImage(
with: url,
options: options,
into: avatarImage
)
}
nameLabel.text = item.name
jobLabel.text = item.job
if item.isBookmark {
bookmarkButton.setImage(UIImage(systemName: "heart.fill"), for: .normal)
} else {
bookmarkButton.setImage(UIImage(systemName: "heart"), for: .normal)
}
}
func bind() {
bookmarkButton.rx.tap
.withUnretained(self)
.bind { owner, _ in
owner.updateBookmark(with: owner.member!)
}
.disposed(by: disposeBag)
}
/// 북마크 업데이트
private func updateBookmark(with member: Member) {
// 1. 로컬데이터 정보 열어보기 - Set타입
var value = UserDefaultManager.bookmark
// 2. value값 업데이트 - Set이라 이미 있으면 반영안돼
if value.contains(member) {
// 2-1. 이미 북마크 했던 값이라면,
// 2-1-1. 북마크 안된 상태의 UI반영
bookmarkButton.setImage(UIImage(systemName: "heart"), for: .normal)
// 2-1-2. value값 변경 - 기존의 값 삭제
value.remove(member)
} else {
// 2-2. 새로 북마크한 값이라면,
// 2-2-1. 북마크한 상태로 UI변경
bookmarkButton.setImage(UIImage(systemName: "heart.fill"), for: .normal)
// 2-2-2. value값 변경 - 값 추가
value.insert(member)
}
// 3. 로컬에 새로운 값 저장
UserDefaultManager.bookmark = value
print("값을 확인해 볼까요? \(UserDefaultManager.bookmark.count)")
}
}
extension MemberCell {
private func setupAvatarImage() {
addSubview(avatarImage)
avatarImage.layer.cornerRadius = 12
avatarImage.backgroundColor = .gray
avatarImage.snp.makeConstraints {
$0.top.leading.equalToSuperview().inset(12)
$0.width.height.equalTo(80)
}
}
private func setupNameLabel() {
addSubview(nameLabel)
nameLabel.adjustsFontSizeToFitWidth = true
nameLabel.snp.makeConstraints {
$0.top.equalTo(avatarImage)
$0.leading.equalTo(avatarImage.snp.trailing).offset(10)
$0.trailing.equalToSuperview().inset(10)
}
}
private func setupJobLabel() {
addSubview(jobLabel)
jobLabel.font = .systemFont(ofSize: 16, weight: .medium)
jobLabel.textColor = .purple
jobLabel.numberOfLines = 0
jobLabel.textAlignment = .left
jobLabel.snp.makeConstraints {
$0.top.equalTo(nameLabel.snp.bottom)
$0.leading.equalTo(nameLabel)
$0.trailing.equalToSuperview().inset(10)
}
}
private func setupBookmarkButton() {
addSubview(bookmarkButton)
bookmarkButton.setImage(UIImage(systemName: "heart"), for: .normal)
bookmarkButton.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.trailing.equalToSuperview().inset(25)
}
}
}
'apple > iOS, UIKit, Documentation' 카테고리의 다른 글
[iOS] FlexLayout을 Cell에서 사용할 때 주의할 점 (0) | 2022.09.02 |
---|---|
[iOS] Swift random String 생성 (0) | 2022.09.01 |
[iOS] UICollectionView에 대해서 알아보기 4편 (Rx + FlexLayout + PinLayout) (0) | 2022.08.31 |
FlexLayout 'YGEnums.h' file not found Error (0) | 2022.08.30 |
[iOS] SwiftUI SceneDelegate, AppDelegate 변경 (0) | 2022.08.25 |