https://github.com/SpartaCoding-iOS05-i/PokeContact/pull/12
#1. 텍스트가 길어지면 이름과 번호가 서로 간섭함 #2. 새 연락처를 추가하면 두 개씩 추가됨 (코드가 꼬였나?) | #3. 번호 입력란에 - 를 추가할 수 없음 → 아예 자동으로 추가되게 구현하면 좋을 것 같음 |
---|---|
#4. TextField를 누르면 아래와 같은 오류가 뜸 |
---|
문제 #1과 문제 #3은 다음에 해결하기로 함
새 연락처를 추가하면 두 개씩 추가됨
onSave
클로저 중복 등록 방지 코드를 추가함
func navigateToAddContact() {
let detailCoordinator = detailCoordinatorFactory() as! DetailCoordinator
let detailViewModel = DetailViewModel(coordinator: detailCoordinator, repository: contactRepository)
let detailViewController = DetailViewController(viewModel: detailViewModel, mode: .add)
detailViewModel.onSave = nil // onSave 클로저가 중복 등록되는 것을 방지
detailViewModel.onSave = { [weak self] (newContact: Contact) in
print("MainCoordinator: onSave called with new contact: \(newContact)")
guard let self = self else { return }
guard let fullName = newContact.fullName, let phoneNumber = newContact.phoneNumber else {
print("Error: Contact data is incomplete")
return
}
do {
try self.contactRepository.addContact(name: fullName, phone: phoneNumber)
print("Added contact successfully.")
self.refreshMainView()
} catch {
print("Failed to add contact: \(error)")
}
}
detailCoordinator.start(with: detailViewController)
childCoordinators.append(detailCoordinator)
}
문제 해결 안됨
CoreData에 Contact
데이터를 저장할 때 중복되는 연락처가 없는지 확인하게 하였다:
func addContact(name: String, phone: String) throws {
// 중복 방지 코드 추가
let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "fullName == %@ AND phoneNumber == %@", name, phone)
let existingContacts = try context.fetch(fetchRequest)
if !existingContacts.isEmpty {
print("ContactRepository: Duplicate contact found, skipping addition")
return
}
// 기존 코드
let contact = Contact(context: context)
contact.fullName = name
contact.phoneNumber = phone
try context.save()
print("ContactRepository: Contact added successfully")
}
두 개씩 추가되는 문제는 해결되긴 했는데, 여전히
addContact
가 두 번 호출되는 것 같다.
ContactRepository: Duplicate contact found, skipping addition
디버깅 메시지가 출력되기 때문
그런데 이 상태로 앱을 껐다 켜보니 데이터가 제대로 저장되지 않는 것을 발견하였다.
디버깅 로그를 분석해보니 ContactRepository
의 중복 확인 로직이 현재 세션의 객체를 중복으로 인식하고 있었다.
찾아보니, CoreData에서의 context
관리 상태와 x-coredata:///
와 x-coredata://
경로의 차이 때문이라고 한다.
DetailViewController
에서 생성된 객체가 NSManagedObjectContext
에 추가되었지만, 아직 저장되지 않은 상태임
x-coredata:///
경로를 가지고 있으며, CoreData의 "임시 객체"로 관리됨addContact
에서 동일한 객체를 중복으로 인식함
fetchRequest
는 이미 생성된 임시 객체를 반환하고, 이를 중복으로 간주하여 추가를 건너뜀MainViewController
에는 새 객체가 보이는 이유:
NSManagedObjectContext
는 저장 여부와 상관없이 관리 중인 모든 객체를 반환하기 때문fetchContacts
와 addContact
메서드에 임시 객체를 제외하는 코드를 넣고,
didTapCreate
메서드에서는 NSManagedObjectContext.save()
를 직접 호출하도록 하였다.
func fetchContacts() throws -> [Contact] {
let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest()
fetchRequest.includesPendingChanges = false // 임시 객체 제외
return try context.fetch(fetchRequest)
}
func addContact(name: String, phone: String) throws {
print("ContactRepository: Adding contact with name: \(name), phone: \(phone)")
let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "fullName == %@ AND phoneNumber == %@", name, phone)
fetchRequest.includesPendingChanges = false // 임시 객체 제외
let existingContacts = try context.fetch(fetchRequest)
print("ContactRepository: Existing contacts for duplication: \(existingContacts)")
if !existingContacts.isEmpty {
print("ContactRepository: Duplicate contact found, skipping addition")
return
}
let contact = Contact(context: context)
contact.fullName = name
contact.phoneNumber = phone
do {
try context.save()
print("ContactRepository: Contact added successfully")
} catch {
print("ContactRepository: Failed to save contact: \(error)")
throw error
}
}
@objc private func didTapCreate() {
print("DetailViewController: didTapCreate called.")
guard let name = nameTextField.text, !name.isEmpty,
let phone = phoneTextField.text, !phone.isEmpty else {
showAlert(message: "All fields are required.")
return
}
let contact = Contact(context: viewModel.repository.context)
contact.fullName = name
contact.phoneNumber = phone
// 객체 저장
do {
try viewModel.repository.context.save() // NSManagedObjectContext.save()를 직접 호출해서 객체 저장
print("DetailViewController: Contact saved in context.")
} catch {
print("DetailViewController: Failed to save context. Error: \(error)")
showAlert(message: "Failed to save contact. Please try again.")
return
}
onSave?(contact)
navigationController?.popViewController(animated: true)
}
문제 해결됨
TextField를 누르면 아래와 같은 오류가 뜸:
Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
If you want to see the backtrace, please set CG_NUMERICS_SHOW_BACKTRACE environmental variable.
버그인 것 같음. 무시해도 괜찮다고 함.