当我重新启动应用程序时,Realm Swift 多对多链接对象不会持续存在

问题描述 投票:0回答:1

我有一个应用程序,可以从 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 如何以多对多关系处理这些链接对象属性。

为什么应用程序重新启动后不保留这些列表属性?

swift realm many-to-many realm-list linkingobjects
1个回答
0
投票

出现了很多问题,所以让我尝试一次性解决所有问题:

这里有一些问题: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 类。

应该可以解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.