[Project 일지] 단어장 앱 만들기 (5)

2024.05.13 - [◽️ Programming/T I L] - [Project 일지] 단어장 앱 만들기 (1)

2024.05.14 - [◽️ Programming/T I L] - [Project 일지] 단어장 앱 만들기 (2)

2024.05.15 - [◽️ Programming/T I L] - [Project 일지] 단어장 앱 만들기 (3)

2024.05.16 - [◽️ Programming/T I L] - [Project 일지] 단어장 앱 만들기 (4)

ImagePicker → PHPicker 변경

이전에 프로필 이미지를 변경했던 내용을 imagePicker로 구현했으나, 기능적인 측면, 앞으로의 방향성 측면에서 PHPicker를 사용하는 점이 좋을 것 같다는 팀원분의 의견에 동의해 변경하는 과정을 거쳤다.

 

생각보다 수월하게 기능 구현이 가능해서 다행이었다.

extension MyPageViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true, completion: nil)
        
        guard let provider = results.first?.itemProvider else { return }
        
        if provider.canLoadObject(ofClass: UIImage.self) {
            provider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
                DispatchQueue.main.async {
                    if let image = image as? UIImage {
                        self?.profileImage.image = image
                    }
                }
            }
        }
    }
}

PHPickerViewControllerDelegate 를 활용해 PHPicker를 불러오고 이미지를 프로필 이미지에 넣어 주는 과정을 넣을 수 있었다.

@objc func changeImageTapped() {
    var configuration = PHPickerConfiguration()
    configuration.filter = .images // 이미지만 사용
    configuration.selectionLimit = 1
    
    let picker = PHPickerViewController(configuration: configuration)
    picker.delegate = self
    present(picker, animated: true, completion: nil)
}

그 다음 이미지 변경 버튼을 눌렀을때 PHPickerConfiguration 를 사용해 불러온 뒤 원하는 세팅을 할 수 있다.

 

.filter 를 통해 동영상 , 이미지 등 다양한 내용을 넣을 수 있고, selectionLimit 을 활용해 한번에 여러장의 사진을 선택할 수 있다.

이렇게 구현하면 손 쉽게 PHPicker로 변경 완료!

 

저장한 날짜를 기준으로 데이터 정렬

코어데이터에 date를 활용해서 저장된 시점의 날짜와 캘린더에서의 날짜를 비교해 같은 날짜에 저장된 단어만 컬렉션 뷰에 나올 수 있도록 구현하였다.

func getWordListFromCoreData(for date: Date) -> [WordEntity] {
    var wordList: [WordEntity] = []
    
    guard let context = managedContext else {
        print("Error: managedContext is nil")
        return wordList
    }
    
    let calendar = Calendar.current
    let startOfDay = calendar.startOfDay(for: date)
    let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)!
    
    let predicate = NSPredicate(format: "(date >= %@) AND (date < %@)", argumentArray: [startOfDay, endOfDay])
    
    let request: NSFetchRequest<WordEntity> = WordEntity.fetchRequest()
    request.predicate = predicate
    
    do {
        wordList = try context.fetch(request)
    } catch {
        print("Failed to fetch word entities:", error)
    }
    return wordList
}

코어 데이터에서 캘린더에 확인되는 날짜의 값만 데이터를 받을 수 있도록 구현하였다. 현재 캘린더 날짜를 가져와 변수에 담고 코어데이터에서 동일한 날짜의 데이터를 갖게 된다.

func calendarView(_ calendarView: UICalendarView, didSelect dateComponents: DateComponents?) {
    selectedDate = dateComponents
    
    fetchWordListAndUpdateCollectionView()
}

캘린더의 날짜를 선택하면 해당하는 날짜를 가져오게 메서드만 불러오면 된다!

외운 단어를 저장하기

컬렉션 뷰 셀에서 내가 해당 단어를 외웠다면 버튼을 체크해 해당 값을 저장하고 그 값을 따로 코어데이터에 저장할 수 있도록 설정했다.

@NSManaged public var memory: Bool

먼저 코어데이터에 해당 값을 추가하고

func updateWordMemoryStatus(word: WordEntity, memory: Bool) {
    guard let context = managedContext else {
        print("Error: managedContext is nil")
        return
    }
    word.memory = memory
    
    do {
        try context.save()
        print("단어의 외운 상태가 업데이트되었습니다.")
    } catch {
        print("단어의 외운 상태를 업데이트하지 못했습니다. 다시 시도해주세요. 오류: \\(error)")
    }
}

코어 데이터에 해당 내용을 따로 저장할 수 있는 메서드를 만들어 외운 단어의 값을 저장한다.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalenderCollectionViewCell.identifier, for: indexPath) as? CalenderCollectionViewCell else { fatalError("컬렉션 뷰 오류") }
    
    let word = filteredWords[indexPath.row]
    cell.configure(with: word)
    cell.learnedButton.tag = indexPath.row
    cell.learnedButton.addTarget(self, action: #selector(learnedButtonTapped(_:)), for: .touchUpInside)
    
    return cell
}

@objc func learnedButtonTapped(_ sender: UIButton) {
    let index = sender.tag
    let word = filteredWords[index]
    let newLearnStatus = !word.memory
    coreDataManager.updateWordMemoryStatus(word: word, memory: newLearnStatus)
    
    sender.isSelected = newLearnStatus
}

그 다음 저장할 컬렉션 뷰를 구성한 VC로 넘어와 단어와 외운 상태의 값을 저장하는 버튼을 눌러 해당 버튼의 값을 저장하도록 설정하면 된다!

func configure(with word: WordEntity) {
    englishLabel.text = word.word
    meaningLabel.text = word.definition
    learnedButton.isSelected = word.memory
}

이렇게 configure 를 통해 컬렉션 뷰 셀에 해당 값을 메서드로 설정해두면 간편하게 해당하는 값이 자동으로 들어가 관리되게 된다.

오늘은 여기까지!