오늘은 과제를 지금까지 작성한 과제를 수정하기 위해 알아야하는 것들에 대해 공부했다. Delegate, DataSource와 같은 개념들과 StackView를 넘어 TableView, Tabbar 등에 대해 공부하고 정리하는 시간을 가졌다.
구현 5는 글자수가 450자 이상일 경우, 말줄임표 표시 및 더보기 버튼 기능 구현이다.
기존의 코드를 수정하여 구현했다.
더보기 버튼과, 상태 저장용 isFolded, 텍스트를 450자로 줄여서 표시할 경우 해당 텍스트를 저자하는 summaryText를 생성한다. onTapExtraButton은 클로져로 생성하여 UserDefaults에 저장되는 부분을 맡게 된다.
let extraButton = UIButton()
private var isFolded = false // 상태 저장용
private var summaryText = "" // 텍스트 저장
var onTapExtraButton: ((Bool) -> Void)?
중요하게 추가된 부분만 발췌하여 표시한다.
// summaryValueLabel.text = summary
self.summaryText = summary // displaySummary에서 사용할 summaryText에 summary 담기
self.isFolded = folded // UserDefaults에서 읽은 데이터의 유무
// summary의 글자수 450 >= 버튼 숨기기
if summary.count >= 450 {
extraButton.isHidden = false
displaySummary()
} else {
extraButton.isHidden = true
summaryValueLabel.text = summary
}
}
// isFolded에 저장된 값이 있을 경우 접혀있는 상태 : 450자 + ..., 더보기 / 값이 없을 경우 더보기 상태 : 글자 전체 출력 + 접기
private func displaySummary() {
if isFolded {
let truncatedText = String(summaryText.prefix(450)) // prefix로 450번째 글자까지 잘라서 truncatedText에 저장
summaryValueLabel.text = truncatedText + "..."
extraButton.setTitle( "더보기", for: .normal)
} else {
summaryValueLabel.text = summaryText
extraButton.setTitle("접기", for: .normal)
}
}
// 버튼 눌렀을 때, 동작하기 위한 함수 생성
@objc
private func extraButtonTapped() {
isFolded.toggle()
displaySummary()
onTapExtraButton?(isFolded)
또한 기존에는, loadBooks 메소드로 책의 데이터를 랜더링하고 있었는데, 표시해야하는 데이터가 증가함에 따라 정보 업데이트 함수를 infoUpdate로 분리하였다. delegate를 사용하여 구현해보고자 했지만, 당시 어떻게 접근을 해야할지 떠올리지 못해서 클로져(onTapExtraButton)를 이용하여 구현했다.
dataService.loadBooks { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let books):
self.books = books
if let firstBook = books.first {
self.infoUpdate(with: firstBook) // 업데이트 정보가 많아져서 함수로 분리
}
case .failure(let error):
print("에러 : \(error)")
}
}
}
// 정보 업데이트 함수 분리
func infoUpdate(with book: Book) {
self.titleText.text = book.title
self.bookInfoView.configure(with: book)
// isFolded_\(book.title) 상대로 저장하는 이유 : 다음 챕터에서 책에 따라 버튼 생성 시 개별적으로 상태 저장하기 위해
let isSaved = UserDefaults.standard.object(forKey: "isFolded_\(book.title)") != nil // UserDefauls에 isFolded_isFolded_\(book.title) 상태로 저장된 값 유무 확인
self.bookSummaryStackView.config(dedication: book.dedication, summary: book.summary, folded: isSaved)
self.bookSummaryStackView.onTapExtraButton = { isFolded in
if isFolded {
UserDefaults.standard.set(true, forKey: "isFolded_\(book.title)") // 접혀있는 상태일 경우, UserDefaults에 isFolded_\(book.title) 형태로 저장
} else {
UserDefaults.standard.removeObject(forKey: "isFolded_\(book.title)") // 더보기 상태일 경우, UserDefaults에 저장된 isFolded_\(book.title) 제거
}
}
self.bookChapterStackView.config(with: book.chapters)
}
//// 접기, 더보기 기능
조건 : 글자 수 450일 경우 표시
상태 : isFolded로 관리 ( true of false : 기본값 false)
만약 글자 수가 450 이상이면 버튼이 표시되어야 함. (extraButton.isHidden = false)
또한 isFolded의 상태에 따라 표시되는 글자 정보가 다름
만약 isFolded가 false이면 접기가 보임
만약 isFolded가 true이면 더보기가 보임 + 450자…
버튼을 눌렀을 때의 동작 순서
버튼을 누르면 isFolded.toggle을 통해 상태를 변환 (true였다면 false로, false 였다면 true)
이후 displaySummary함수를 호출하여 표시를 달리하고, onTapExtraButton함수에 isFolded를 담아서 보냄
ViewController에서 isFolded의 상태를 받아서 isSaved에 저장함
onTapExtraButton을 클로저로 만들어 둔 이유 : 쪽지만 전달하고 아직 펼치지는 않았으면 한다.
즉 버튼을 클릭할 경우에 onTapExtraButton이 실행이됨.
ViewController의 infoUpdate 메서드 내부에 onTapExtraButton이 명시되어 있다고 해도, onTapExtraButton이 계속 실행되는 것이 아님. 버튼을 눌렀을 때만 실행이됨. + 버튼을 누를 경우 저 부분만 실행
Delegate
ref. https://weekoding.tistory.com/13
ref. https://velog.io/@nala/iOS-Delegate-%ED%8C%A8%ED%84%B4%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90
DateFormatter
ref. https://bibi6666667.tistory.com/521