🧑🏻💻 Level 5 - CoreData를 사용하여 연락처 데이터 디스크에 저장하고 불러오기
CoreData 방식, UserDefaults 방식 모두 구현해보세요.)UINavigationController.popViewController 이용.import Foundation
import CoreData
import UIKit
class CoreDataManager {
// 싱글톤
static let shared = CoreDataManager(container: (UIApplication.shared.delegate as! AppDelegate).persistentContainer)
var container: NSPersistentContainer!
var phoneBooks: [NSManagedObject] = []
// 초기화
init(container: NSPersistentContainer!) {
self.container = container
}
// 데이터 저장
func createData(imageUrl: String?, name: String, phoneNumber: String) {
guard let entity = NSEntityDescription.entity(forEntityName: "PhoneBook", in: self.container.viewContext) else { return }
let newPhoneBook = NSManagedObject(entity: entity, insertInto: self.container.viewContext)
newPhoneBook.setValue(name, forKey: "name")
newPhoneBook.setValue(phoneNumber, forKey: "phoneNumber")
// UIImage를 CoreData에 저장하려면 Data 타입으로 변환해야 됨.
if let imageUrl = imageUrl {
newPhoneBook.setValue(imageUrl, forKey: "imageUrl")
}
do {
try self.container.viewContext.save()
print("문맥 저장 성공")
} catch {
print("문맥 저장 실패")
}
}
// 데이터 읽기
func readAllData() {
// 데이터 요청
let request = NSFetchRequest<NSManagedObject>(entityName: "PhoneBook")
// 이름 순으로 정렬 (오름차순)
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
// 정렬 기준 적용
request.sortDescriptors = [sortDescriptor]
do {
phoneBooks = try self.container.viewContext.fetch(request)
for phoneBook in phoneBooks as [NSManagedObject] {
let name = phoneBook.value(forKey: "name") as? String ?? "이름 없음"
let phoneNumber = phoneBook.value(forKey: "phoneNumber") as? String ?? "번호 없음"
if let image = phoneBook.value(forKey: "imageUrl") as? String {
print("imageUrl: \(image), name: \(name), phoneNumber: \(phoneNumber)")
} else {
print("imageUrl: 이미지 없음, name: \(name), phoneNumber: \(phoneNumber)")
}
}
} catch {
print("데이터 읽기 실패")
}
}
}
import UIKit
import CoreData
class PhoneBookViewController: UIViewController {
private var profileImageUrl: String? // imageUrlString 저장할 프로퍼티 추가
.
.
.
@objc
private func didApplyButtonTapped() {
print("적용 버튼이 탭 되었습니다.")
CoreDataManager.shared.createData(
imageUrl: profileImageUrl,
name: nameTextField.text ?? "",
phoneNumber: phoneNumTextField.text ?? "")
self.navigationController?.popViewController(animated: true) // 전 화면으로 돌아가기
}
@objc
private func ramdomImageGenerationButtonTapped() {
print("랜덤 이미지를 생성합니다.")
FetchAPI.shared.fetchPokemonImage { [weak self] image, imageUrlStr in
guard let self else { return }
DispatchQueue.main.async {
self.profileImageView.image = image
self.profileImageUrl = imageUrlStr // CoreData에 저장
}
}
}
}
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear")
// 네비게이션 바 숨기기
self.navigationController?.setNavigationBarHidden(true, animated: false)
CoreDataManager.shared.readAllData()
tableView.reloadData()
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return CoreDataManager.shared.phoneBooks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: PhoneBookTableViewCell.id, for: indexPath) as? PhoneBookTableViewCell else { return UITableViewCell() }
let phoneBook = CoreDataManager.shared.phoneBooks[indexPath.row]
let imageUrl = phoneBook.value(forKey: "imageUrl") as? String ?? ""
let name = phoneBook.value(forKey: "name") as? String ?? ""
let phoneNumber = phoneBook.value(forKey: "phoneNumber") as? String ?? ""
cell.configureCell(imageUrl: imageUrl, name: name, phoneNumber: phoneNumber)
return cell
}
}
import UIKit
class PhoneBookTableViewCell: UITableViewCell {
public func configureCell(imageUrl: String?, name: String, phoneNumber: String) {
nameLabel.text = name
phoneNumLabel.text = phoneNumber
// 이미지 URL이 없다면 기본 이미지로 설정
guard let imageUrl = imageUrl, let url = URL(string: imageUrl) else {
pokemonImageView.image = nil
return
}
// URLSession으로 비동기 이미지 로드
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard let self = self else { return }
if let data = data, let image = UIImage(data: data) {
DispatchQueue.main.async {
self.pokemonImageView.image = image
}
} else {
DispatchQueue.main.async {
self.pokemonImageView.image = nil // 실패 시 기본 이미지 설정
}
}
}.resume()
}
}
