'RLMException',原因:'从错误的线程访问领域。'

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

我需要将我的人物模型写入领域数据库。我从来不明白这意味着什么,因为我正在使用一个 Realm 实例,并且我认为我正在使用同一个线程。我错了吗??

 func updatePerson(ps:personTmp){



        let db=fetchPerson()

        guard let url=URL(string: "\(address)pe?Authorization=\(db.serverToken)") else {return}

        var urlRequest=URLRequest(url: url)

        urlRequest.httpMethod="PUT"
        urlRequest.addValue("Application/Json", forHTTPHeaderField: "Content-type")

        print(ps.dictionary)
        let body = try! JSONSerialization.data(withJSONObject: ps.toJSON(), options: .prettyPrinted)

         urlRequest.httpBody=body

        URLSession.shared.dataTask(with: urlRequest) { (data, response, err) in


            if let content=data {

                let json = try! JSONSerialization.jsonObject(with: content, options: .allowFragments) as! [String:AnyObject]

                let ersonJson =  json["data"] as! AnyObject

                let tmp = Mapper<person>().map(JSONObject: ersonJson)!
                tmp.serverToken = db.serverToken

                print(tmp)

                     self.dbManager.deleteAllFromDatabase()

                            if self.dbManager.saveData(ps: tmp) {


                            }
}

这是我的

class databaseManager {


    var database:Realm
    //var shareInstance=databaseManager()

     static let share=databaseManager()
    var config = Realm.Configuration()

    init() {
        config = Realm.Configuration(

            // set a new version number, the version number must bigger than before

            // if you never set it, it's 0

            schemaVersion: 1,

            migrationBlock: { migration, oldSchemaVersion in

                if (oldSchemaVersion < 1) {
                    // do nothing
                }
        })

        // tell Realm the new config should be used

        Realm.Configuration.defaultConfiguration = config

        // open realm file and it will do auto-migration



        self.database = try! Realm()
    }




    func fetchData() ->   person {

        let nill=person()

        DispatchQueue.global(qos: .background).async {

        Realm.Configuration.defaultConfiguration = self.config

        }

        if let results =  self.database.objects(person.self).first {

            return results

        }else {

            return nill
        }



    }





    func saveData(ps: person) ->Bool  {

        var bool:Bool?



            try! self.database.write {

                if (ps.serverToken.isEmpty || ps.identityId.isEmpty) {
                    bool=false

                }else {
                    bool = true
                    self.database.add(ps, update: true)

                }

            }



        return bool!


}





    func deleteAllFromDatabase()  {



        DispatchQueue.main.async {

            try!   self.database.write {

                self.database.deleteAll()

            }

        }


    }

你能告诉我我的保存功能有什么问题吗?我会做什么? 我怎样才能在没有线程冲突的情况下编写我的模型?

ios swift xcode multithreading realm
2个回答
4
投票

使用单例并不意味着它总是在同一个线程上调用......例如..

// 1. here you are likely in the main thread
URLSession.shared.dataTask(with: urlRequest) { (data, response, err) in 
   // 2. here you are in a background thread
}

您的单例 (

databaseManager
) 可能已在主线程上创建。当您处于异步函数的闭包内(如上面第 2 点所示)时,您就处于后台线程中。因此,如果您在后台线程中创建对象,然后将其传递给数据库管理器进行保存,则您会将在后台线程上创建的对象传递给在主线程上创建的领域实例。导致你的问题。

如果我没记错的话,你应该能够在闭包内分派到主线程并摆脱这个错误:

DispatchQueue.main.async {
    let json = try! JSONSerialization.jsonObject(with: content, options: .allowFragments) as! [String:AnyObject]
    let ersonJson =  json["data"] as! AnyObject
    let tmp = Mapper<person>().map(JSONObject: ersonJson)!
    tmp.serverToken = db.serverToken

    self.dbManager.deleteAllFromDatabase()
    if self.dbManager.saveData(ps: tmp) {

    }
}

0
投票

有时,当我们使用 SwiftUI 中发布的属性时,Realm 会抛出此错误。原因之一是线程 com.apple.swiftui.asyncRenderer 间接执行从 Realm 查找对象的调用,因此您不应该直接从 Realm 对象获得引用。

假设您的视图中有这个已发布的变量:

@Published var notifications: Notification

然后您可以使用以下代码从 Realm 获取通知:

notifications = realmInstance.objects(Notification.self)

当视图更新时,可能会触发 com.apple.swiftui.asyncRenderer 中的这些更新,从而可能导致应用程序崩溃。

解决此问题的一种方法是创建检索到的对象的副本,如下所示:

extension Notification: NSCopying {
    func copy(with zone: NSZone? = nil) -> Any {
        return Notification(id)
    }
}
notifications = realmInstance.objects(Notification.self).copy()

这种方法可以帮助减少错误并防止崩溃,因为它可以防止您的视图直接从 Realm 请求模型

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