I have an app that successfully retrieves iOS contacts from the UI and then creates “ProductionContact” objects from these.
class Shoot: Object {
@objc dynamic var id: String = NSUUID().uuidString
override class func primaryKey() -> String? {
return "id"
}
// each shoot can have many ProductionContacts
var productionContacts = List<ProductionContact>()
}
class Production: Object {
@objc dynamic var id: String = NSUUID().uuidString
override class func primaryKey() -> String? {
return "id"
}
// each Production can have many ProductionContacts
var productionContacts = List<ProductionContact>()
}
class ProductionContact: Object {
@objc dynamic var id: String = NSUUID().uuidString
// inverse of List<ProductionContact>() relationship in Shoot object
var shoots = LinkingObjects(fromType: Shoot.self, property: "productionContacts")
// inverse of List<ProductionContact>() relationship in Production object
var productions = LinkingObjects(fromType: Production.self, property: "productionContacts")
@objc dynamic var firstName: String = ""
@objc dynamic var lastName: String = ""
@objc dynamic var title: String = ""
@objc dynamic var phone: String = ""
@objc dynamic var email: String = ""
@objc dynamic var url: String = ""
@objc dynamic var socialPlatform: String = ""
@objc dynamic var socialHandle: String = ""
@objc dynamic var IMDbUrl: String = ""
@objc dynamic var notes: String = ""
}
When I write these new objects the list property “productionContacts” in the Shoot and Production objects, realm seems to write the data fine. The list property “productionContacts” in both the Shoot and Production objects contains the new ProductionContact objects.
The problem is when I restart the app, all the other properties and objects are intact, but the list property “productionContacts” is empty, and the associations between them are lost. I have scoured my code and there is no place where I change the list property “productionContacts” in either the Shoot or Production objects.
I feel like don’t fully understand how RealmSwift handles these linking object properties.
func fetchContactImageUrls(from contacts: [CNContact], completion: @escaping(Bool?) -> Void) {
let dispatchGroup = DispatchGroup()
for contact in contacts {
dispatchGroup.enter()
if contact.imageDataAvailable, let imageData = contact.imageData, let image = UIImage(data: imageData) {
// image found, save to camera roll and update image url
let identifier = contact.identifier
ImageManager.instance.createAlbum(image: image) { localID in
guard let localID = localID else { return }
print(localID)
self.imageUrls[identifier] = localID
dispatchGroup.leave()
}
} else {
// no image found
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: DispatchQueue.main, execute: {
print("Fetched image urls if there were any")
if self.imageUrls.count > 0 {
completion(true)
} else {
completion(false)
}
})
}
func createProductionContactsFromiOSContacts(_ contacts: [CNContact]) -> [ProductionContact] {
var localPCs = [ProductionContact]()
contacts.forEach({
let pC = ProductionContact()
pC.iOSContactIDKey = $0.identifier
pC.firstName = $0.givenName.isEmpty ? "No First Name" : $0.givenName
pC.lastName = $0.familyName.isEmpty ? "No Last Name" : $0.familyName
pC.title = $0.jobTitle.isEmpty ? "No Job Title" : $0.jobTitle
pC.email = ($0.emailAddresses.first?.value as? String) ?? ""
pC.phone = ($0.phoneNumbers.first?.value as? CNPhoneNumber)?.stringValue ?? ""
pC.socialHandle = ($0.socialProfiles.first?.value as? CNSocialProfile)?.username ?? ""
pC.socialPlatform = ($0.socialProfiles.first?.label as? String) ?? ""
pC.image = imageUrls[$0.identifier] ?? ""
localPCs.append(pC)
})
print("created (localPCs.count) Production Contacts from iOS contacts")
return localPCs
}
func addContactsToRealm(_ contacts: [CNContact]) {
fetchContactImageUrls(from: contacts) { listHasImages in
guard let listHasImages = listHasImages else { return }
self.addPCsToRealm()
}
}
func addPCsToRealm() {
do {
try realm.write {
self.pCs = self.createProductionContactsFromiOSContacts(contacts)
realm.add(self.pCs)
guard let shoot = self.selectedShoot else { return }
guard let production = shoot.production else { return }
shoot.productionContacts.append(objectsIn: self.pCs)
production.productionContacts.append(objectsIn: self.pCs)
}
} catch {
print("error adding contact to production or shoot. Not sure which tho.")
}
guard let sid = id else { return }
self.reloadOnSet(id: sid)
}
func contactPicker(didSelect contacts: [CNContact]) {
self.contacts.append(contentsOf: contacts)
self.addContactsToRealm(contacts)
}