swift realm :: IncorrectThreadException:从错误的线程访问Realm

时间:2016-10-23 10:30:01

标签: ios multithreading realm

我创建了一个名为" File"的模型,它在Realm Browser中看起来很不错: Realm Browser

但是当我使用该模型时,它将返回错误: libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.

在我的代码中,我在每个需要添加/更新的位置创建了Realm对象:

private var allFiles : Results<File>!

private var downloadingFiles : Results<File>! {
    return self.allFiles.filter("completed = false")
}

private var downloadedFiles : Results<File>! {
    return self.allFiles.filter("completed = true")
}

private var downloading = false

private var request: Alamofire.Request?

func download() {

    let fileRealm = try! Realm()
    allFiles = fileRealm.objects(File).sorted("updatedAt")

    downloadFile()
}

private func downloadFile() {

    if !self.downloading, let file = self.downloadingFiles.first where !file.completed {

        self.reqForDownload(file)
    }
}

private func reqForDownload(file: File) -> Void {

    downloading = true

    request = Alamofire
        .download(.GET, file.url, destination: { (url, response) -> NSURL in

            return NSURL(fileURLWithPath: file.filePath)

        })
        .progress { [unowned self](bytesRead, totalBytesRead, totalBytesExpectedToRead) in
            dispatch_async(dispatch_get_main_queue(), {
                let variable = Float(totalBytesRead)/Float(totalBytesExpectedToRead)
                debugPrint(variable)
            })
        }
        .response { [unowned self](request, response, data, error) in
            if let error = error {

                dispatch_async(dispatch_get_main_queue(), {
                    let fileRealm = try! Realm()
                    try! fileRealm.write({
                        file.completed = false
                    })
                    self.allFiles = fileRealm.objects(File).sorted("updatedAt")
                })

                if error.code == NSURLErrorCancelled {
                    debugPrint("Canceled download")
                }

            } else {
                debugPrint("Downloaded file successfully")

                dispatch_async(dispatch_get_main_queue(), {
                    let fileRealm = try! Realm()
                    try! fileRealm.write({
                        file.completed = true
                    })
                    self.allFiles = fileRealm.objects(File).sorted("updatedAt")
                })
            }

            self.downloading = false 
    }
}

我是Realm的新手,但我知道Realm不是线程安全的,所以我试图在主线程中使用该对象作为我的代码,但错误仍然出现。请有人帮助我,谢谢。

我已将我的代码更新为@ TimOliver&#39; suggest,但它仍会响应相同的错误。新代码如下:

private var allFiles : Results<File>!

private var downloadingFiles : Results<File>! {
    return self.allFiles.filter("completed = false")
}

private var downloadedFiles : Results<File>! {
    return self.allFiles.filter("completed = true")
}

private var downloading = false

private var request: Alamofire.Request?

func download() {

    let fileRealm = try! Realm()
    allFiles = fileRealm.objects(File).sorted("updatedAt")

    downloadFile()
}

private func downloadFile() {

    if !self.downloading, let file = self.downloadingFiles.first where !file.completed {

        self.reqForDownload(file)
    }
}

private func reqForDownload(file: File) -> Void {

    downloading = true

    request = Alamofire
        .download(.GET, file.url, destination: { (url, response) -> NSURL in

            return NSURL(fileURLWithPath: file.filePath)

        })
        .progress { [unowned self](bytesRead, totalBytesRead, totalBytesExpectedToRead) in
            dispatch_async(dispatch_get_main_queue(), {
                let variable = Float(totalBytesRead)/Float(totalBytesExpectedToRead)
                debugPrint(variable)
            })
        }
        .response { [unowned self](request, response, data, error) in
            if let error = error {

                let fileRealm = try! Realm()
                    try! fileRealm.write({
                        file.completed = false
                    })
                    self.allFiles = fileRealm.objects(File.self).sorted("updatedAt")

                if error.code == NSURLErrorCancelled {
                    debugPrint("Canceled download")
                }

            } else {
                debugPrint("Downloaded file successfully")

                let fileRealm = try! Realm()
                    try! fileRealm.write({
                        file.completed = true
                    })
                    self.allFiles = fileRealm.objects(File.self).sorted("updatedAt")
            }

            self.downloading = false 
    }
}

2 个答案:

答案 0 :(得分:2)

就像我在评论中提到的那样,如果你设置了一个异常断点,你可以确切地看到哪一行代码触发了Realm异常,这样你就可以跟踪Realm事务发生在哪个线程,以及哪些对象正在进行交互。用它。

如果我没记错的话,我相信默认情况下在主线程上调用该方法的.response部分中的闭包,但是你试图修改{{ 1}}在主线程上明确查询的对象。

如果强制在主线程上调用每个闭包,那么在file对象中拥有primary key属性,直接保存对主键值的引用会更合适,然后在需要更新它时直接查询file对象的线程本地版本(即使用Realm.object(ofType: primaryKey:)方法。

答案 1 :(得分:1)

self.allFiles = fileRealm.objects(File.self).sorted("updatedAt")关闭中的

.response()被解除了子线程。所以你稍后在主线程上访问self.allFiles,它会崩溃。

  

结果实例是对基础数据的实时自动更新视图,这意味着永远不必重新获取结果。它们总是在当前线程上反映Realm的当前状态,包括在当前线程的写入事务期间。

https://realm.io/docs/swift/latest/#auto-updating-results

因此您无需重新获取allFiles。交易已提交,allFiles会自动更新。