오늘은 필수 구현 과제6에 대해 작성을 하고 구현을 하며 고려했던 사항, 겪었던 문제점들을 기록하고자 한다.
기존에는 기본적으로 버튼 하나만을 생성했었다. 그러나 시리즈 버튼의 개수를 data.json의 attributes의 개수에 맞게 동적으로 표시하고자 했으며, 이 버튼들을 하나로 담아두는 stackView를 사용했다
seriesButton.setTitle("1", for: .normal)
seriesButton.setTitleColor(.white , for: .normal)
seriesButton.titleLabel?.font = .systemFont(ofSize: 16)
seriesButton.backgroundColor = .systemBlue
seriesButton.layer.cornerRadius = 8
[titleText, seriesButton, scrollView].forEach { view.addSubview($0) }
seriesButton.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.top.equalTo(titleText.snp.bottom).offset(16)
$0.width.equalTo(seriesButton.snp.height) // height에 width 고정 -> 가로, 세로 비율 유지
}
seriesStackView.axis = .horizontal
seriesStackView.spacing = 6
seriesStackView.distribution = .fillEqually
seriesStackView.alignment = .center
[titleText, seriesStackView, scrollView].forEach { view.addSubview($0) }
seriesStackView.snp.makeConstraints {
$0.centerX.equalToSuperview()
$0.top.equalTo(titleText.snp.bottom).offset(16)
}
-stackView 내부 버튼 생성, 속성 정의, 동작
// 버튼 관련 메소드 관리
extension ViewController {
// 기존 : 버튼 1개 생성 -> 배열로 받아와서 개수만큼 버튼 생성
private func setSeriesButton(with books: [Book]) {
// 기본 버튼 생성, 속성 정의
for idx in books.indices {
let button = SeriesButton()
button.setTitle("\(idx + 1)", for: .normal)
button.setTitleColor(.systemBlue, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 16)
button.backgroundColor = .systemGray5
button.tag = idx
button.addTarget(self, action: #selector(seriesButtonTapped(_:)), for: .touchDown)
button.snp.makeConstraints {
$0.width.equalTo(button.snp.height)
}
seriesStackView.addArrangedSubview(button)
seriesButtons.append(button)
}
}
// 버튼을 눌렀을 때, 동작하는 메서드 정의
@objc
private func seriesButtonTapped(_ sender: SeriesButton) {
let idx = sender.tag
let book = books[idx]
infoUpdate(with: book)
self.scrollView.setContentOffset(.zero, animated: false) // 스크롤 위치 초기화
selectedSeriesButton(idx)
}
// 버튼 눌렸을 때 상태 변화 메서드 정의
private func selectedSeriesButton(_ selectedSeriesIdx: Int) {
for (idx, btn) in seriesButtons.enumerated() {
btn.backgroundColor = (idx == selectedSeriesIdx) ? .systemBlue : .systemGray5
let titleColor: UIColor = (idx == selectedSeriesIdx) ? .white : .systemBlue
btn.setTitleColor(titleColor, for: .normal)
}
}
}
문제의 요구사항에 맞게(이후 확인한 조금 놓친 부분들이 있지만), 구현을 완료했다. 지금까지의 구현을 하며 문제를 겪었던 부분들과 이해를 요했던 것들을 정리하자.
데이터는 data[attributes[ @@@@@@@@@]]로 존재한다.
그러므로 객체를 3개로 생성해야 함
data를 담는 BookResponse
attributes를 담는 BookData
title, author, pages, releaseDate, summary, dedication, chapters[]를 담는 Book
조건 : releaseDate는 data.json에서 release_date로 존재함.
그러므로 enum을 사용하여 releaseDate = “release_date” 로 데이터 넣어주기
또한 Book 구조체 내부의 chapters는 배열로 넘어오기에 Chapter 구조체 생성 내부는 title
불러온 데이터 사용
BookInfoStackView.swift -> title, author, releaseDate, pages
BookSummaryStackView.swift -> summary,dedication
BookChapterStackView.swift -> forEach를 사용하여 chapter.title를 StackView에 넣기
ViewController.swift에서 seriesButton을 배열로 생성
setSeriesButton 메소드 생성
Book 배열을 books로 받아와서 books.indices 만큼 반복을 진행하여 버튼 생성 -> StackView에 넣기
생성 시에 button.tag를 사용하여 각각에 인덱스 값을 입력하여 생성
버튼 눌렀을 때 동작 : seriesButtonTapped 메소드를 생성하여 sender(button의 tag를 인덱스로 받아서 책의 정보를 전환, 스크롤 위치 초기화, selectedSeriesButton 메소드를 정의하고 사용하여 색상 변화
BookSummaryStackView.swift에서 접기/더보기 기능을 구현하였으며, 이 정보는 UserDefaults에 저장되어야 한다. 현재의 코드에서는 클로져를 사용하여 구현하였으나, delegate를 사용하여 구현할 수 있는데, 어떻게 적용할 것인가?
BookSummaryStackView에 protocol 생성( Delegate)
onTapExtraButton(isFolded: Bool) 메소드 생성
클래스 본체에 weak var deleagte: BookSummaryStackViewDelegate? 선언 : 보고 받을 대상 변수 생성
ViewController의 configUI에 bookSummaryStackView.delegate = self 선언 : 보고 받을 대상 지정
protocol 메서드 onTapExtraButton 내부 동작 명세 (기존 코드 사용 -> book.title은 사용할 수 없음 : 버튼이 눌리는 시점에 보고를 받음 고로 titleTex.text를 저장, 삭제)
기본 구현에서 깜빡했던 titleImage를 동적으로 랜더링하는 코드를 어떻게 구성할 것인가? titleImage에 대한 정보는 data.json에서 제공하지 않음.
버튼을 눌렀을 때 동작하는 메소드인 seriesButtonTapped에서 sender(SeriesButton)의 tag를 idx로 저장하고 있으므로, infoUpdate를 호출할 때 book과 함께 idx를 넘겨주도록 구현. 또한, 화면에 표시되는 titleImage는 UIImage(named: "harrypotter(idx +1)")로 선언하여 asset에 있는 이미지에 연결
기본적으로 넘어오는 release_date(String 타입, yyyy-MM-dd 형태)를 MMMM(July) d, yyyy 형태로 변경해야 함.
구상안
받아온 String 타입의 releaseDate를 Date 타입으로 변경 후 yyyy-MM-dd 형식을 MMMM d, yyyy 형식으로 변경함(Date 타입) 또한, Locale(identifier: "en_US")를 사용하여 July 형태로 표시 이후 String타입으로 다시 변환하여 return
고려사항 : String -> Date -> String 형식 변환이 많은데, 불필요하지 않나 ?
해당 내용은 내일 정리할 것이다.