I am trying to make CNMutableContact "Codable". I have already built the encode function (see below), but I am getting some issues to decode array such as postalAddresses, emailAddresses, etc.
Here is my encode function:
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.contact.contactType.rawValue, forKey: .contactType)
try container.encode(self.contact.namePrefix, forKey: .namePrefix)
try container.encode(self.contact.givenName, forKey: .givenName)
try container.encode(self.contact.middleName, forKey: .middleName)
try container.encode(self.contact.familyName, forKey: .familyName)
try container.encode(self.contact.previousFamilyName, forKey: .previousFamilyName)
try container.encode(self.contact.nameSuffix, forKey: .nameSuffix)
try container.encode(self.contact.nickname, forKey: .nickname)
try container.encode(self.contact.jobTitle, forKey: .jobTitle)
try container.encode(self.contact.departmentName, forKey: .departmentName)
try container.encode(self.contact.organizationName, forKey: .organizationName)
var postalAddresses: [String:String] = [:]
self.contact.postalAddresses.forEach { postalAddress in
postalAddresses[postalAddress.label ?? "postal\(String(describing: index))"] = (CNPostalAddressFormatter.string(from: postalAddress.value, style: .mailingAddress))
}
try container.encode(postalAddresses, forKey: .postalAddresses)
var emailAddresses: [String:String] = [:]
self.contact.emailAddresses.forEach { emailAddress in
emailAddresses[emailAddress.label ?? "email\(String(describing: index))"] = (emailAddress.value as String)
}
try container.encode(emailAddresses, forKey: .emailAddresses)
var urlAddresses: [String:String] = [:]
self.contact.urlAddresses.forEach { urlAddress in
urlAddresses[urlAddress.label ?? "url\(String(describing: index))"] = (urlAddress.value as String)
}
try container.encode(urlAddresses, forKey: .urlAddresses)
var phoneNumbers: [String:String] = [:]
self.contact.phoneNumbers.forEach { phoneNumber in
phoneNumbers[phoneNumber.label ?? "phone\(String(describing: index))"] = phoneNumber.value.stringValue
}
try container.encode(phoneNumbers, forKey: .phoneNumbers)
var socialProfiles: [String:String] = [:]
self.contact.socialProfiles.forEach { socialProfile in
socialProfiles[socialProfile.label ?? "social\(String(describing: index))"] = socialProfile.value.urlString
}
try container.encode(socialProfiles, forKey: .socialProfiles)
try container.encode(self.contact.birthday, forKey: .birthday)
try container.encode(self.contact.note, forKey: .note)
}
As you can see, I encode the postalAddresses this way:
var postalAddresses: [String:String] = [:]
self.contact.postalAddresses.forEach { postalAddress in
postalAddresses[postalAddress.label ?? "postal\(String(describing: index))"] = (CNPostalAddressFormatter.string(from: postalAddress.value, style: .mailingAddress))
}
try container.encode(postalAddresses, forKey: .postalAddresses)
But I have some difficulties to understand exactly how to decode it. Here is my decode function (not complete):
init(from decoder: Decoder) throws {
let decodedContact = try decoder.container(keyedBy: CodingKeys.self)
id = try decodedContact.decode(UUID.self, forKey: .id)
contactIdentifier = try decodedContact.decode(String.self, forKey: .contactIdentifier)
contact = CNMutableContact()
var intContactType = try decodedContact.decode(Int.self, forKey: .contactType)
if intContactType == 0 {
contact.contactType = CNContactType.person
} else {
contact.contactType = CNContactType.organization
}
contact.namePrefix = try decodedContact.decode(String.self, forKey: .namePrefix)
contact.givenName = try decodedContact.decode(String.self, forKey: .givenName)
contact.middleName = try decodedContact.decode(String.self, forKey: .middleName)
contact.familyName = try decodedContact.decode(String.self, forKey: .familyName)
contact.previousFamilyName = try decodedContact.decode(String.self, forKey: .previousFamilyName)
contact.nameSuffix = try decodedContact.decode(String.self, forKey: .nameSuffix)
contact.nickname = try decodedContact.decode(String.self, forKey: .nickname)
contact.jobTitle = try decodedContact.decode(String.self, forKey: .jobTitle)
contact.departmentName = try decodedContact.decode(String.self, forKey: .departmentName)
contact.organizationName = try decodedContact.decode(String.self, forKey: .organizationName)
// MISSING ARRAYS
let postalAddresses = try decodedContact.decode([String:String], forKey: .postalAddresses)
contact.birthday = try decodedContact.decode(DateComponents.self, forKey: .birthday)
contact.note = try decodedContact.decode(String.self, forKey: .note)
}
Note: the decode function returns an error with the postalAdresses decoding line.
Can you help me understand if my approach is correct and how to decode arrays?
Thanks
I have tried different ways to decode postalAddresses, but always getting an error.
It's not necessary to reinvent the wheel.
CN(Mutable)Contactconforms toNSSecureCoding, it can be serialized toData.And in Swift there is the PropertyWrapper pattern which exposes the instance and can perform the en-/decoding stuff under the hood
In your struct declare