我有一个应用程序,可以从 UI 检索 iOS 联系人,然后从中创建“ProductionContact”对象。我的目标是将这些联系人分配给众多现有的拍摄和制作。第一次运行似乎一切正常。
以下是对象模型:
class Production: Object {
@objc dynamic var id: String = NSUUID().uuidString
override class func primaryKey() -> String? {
return "id"
}
// each production can have many shoots
let shoots = List<Shoot>()
// each Production can have many ProductionContacts
var productionContacts = List<ProductionContact>()
}
class Shoot: Object {
@objc dynamic var id: String = NSUUID().uuidString
override class func primaryKey() -> String? {
return "id"
}
// each shoot has only one production
@objc dynamic var production: Production?
var productions = LinkingObjects(fromType: Production.self, property: "shoots")
// each shoot 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 = ""
}
当我将这些新对象写入现有 Shoot 和 Production 对象中的列表属性“developmentContacts”时,realm 似乎可以很好地写入数据。 Shoot 和 Production 对象中的列表属性“developmentContacts”都包含新的 ProductionContact 对象。我可以浏览应用程序并且保留数据。
以下是我正在使用的功能:
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)
}
问题是,当我重新启动应用程序并列出 Production Contacts 时,所有属性和对象都完好无损 - 除了 Shoot 和 Production 对象中的列表属性“productContacts”。它是空的,他们之间的关系也消失了。我已经检查了我的代码,没有其他地方可以更改 Shoot 或 Production 对象中的列表属性“developmentContacts”。
我觉得我没有完全理解 RealmSwift 如何以多对多关系处理这些链接对象属性。
为什么应用程序重新启动后不保留这些列表属性?
出现了很多问题,所以让我尝试一次性解决所有问题:
这里有一些问题:ObjC 与 Swift 结构混合在一起,变量声明不正确(ObjC List 必须是 let),ObjC 实现是针对旧 SDK 的,逆向关系没有正确的语法。要修复此问题,请将对象更新为 Swift:
这个
class Production: Object {
@objc dynamic var id: String = NSUUID().uuidString
override class func primaryKey() -> String? {
return "id"
}
let shoots = List<Shoot>() //note this is a let
var productionContacts = List<ProductionContact>() //note this is a **var**
}
应该是
class Production: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var shoots = RealmSwift.List<Shoot>()
@Persisted var productionContacts = RealmSwift.List<ProductionContact>()
}
然后一个逆关系的例子是:
class ProductionContact: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted(originProperty: "productionContacts") var productions: LinkingObjects<Production>
@Persisted(originProperty: "shoots") var shoots: LinkingObjects<Shoot>
您可以更新 Shoot 类。
应该可以解决这个问题。