使用Swift-4.0.3,RealmSwift-3.0.2,iOS-11.2.6和Xcode-9.2
我尝试通过URLSession回调(didFinishDownloadingTo
)更新Realm对象 - 请参阅下面的代码。多次输入此回调,直到完成文件的完整下载。为了保持下载状态的持久信息,我想使用领域对象。
出于某种原因,这还不行。我得到以下异常:
Main Thread Checker: UI API called on a background thread: -[UIProgressView progress]
PID: 7200, TID: 113132, Thread name: (none), Queue name: NSOperationQueue 0x60000023e8a0 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4
有什么问题? (另外,调度到主队列或后台没有帮助)!
extension DetailDBFileDownloaderViewController: URLSessionDownloadDelegate {
let downloadService = MyDownloadService()
//... not all needed delegate-methods shown....
// delegete method firing every time another chunk of a large-file has been downloaded...
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
// ...
let tempDownloadEntry = DownloaderItem()
tempDownlaodEntry.identifier = self.someID
tempDownloadEntry.someProperty = self.somePoperty
tempDownloadEntry.DBFile.index = self.someOtherID
tempDownlaodEntry.DBFile.moreProp = self.someotherProperty
// ...
let entryRealm = try? Realm()
if let rlm = entryRealm {
let predicate = NSPredicate(format: "title == %@", self.titleLabelString!)
let myTitles = rlm.objects(DownloaderTitleSet.self).filter(predicate)
if (myTitles.count == 0) {
// !!!! FIRST ROUND WORKS (i.e. Realm still empty) !!!!
rlm.beginWrite()
let newTitleSet = DownloaderTitleSet()
newTitleSet.title = self.titleLabelString!
newTitleSet.version = self.versionLabelString ?? "0.0.0"
newTitleSet.lastItemIndex = self.someID
newTitleSet.downloaderItems.append(tempDownloadEntry)
rlm.add(newTitleSet, update: true)
try! rlm.commitWrite()
} else if (myTitles.count == 1) {
// !!!! SECOND, THIRD, etc. round does not work !!!!!!!
rlm.beginWrite()
let existingTitleSet = myTitles.first
// !!!!! Here is where the exception happens !!!!!!!!
existingTitleSet?.title = self.titleLabelString!
existingTitleSet?.version = self.versionLabelString ?? "0.0.0"
existingTitleSet?.lastItemIndex = self.someID
existingTitleSet?.downloaderItems.append(tempDownloadEntry)
rlm.add(existingTitleSet!, update: true)
try! rlm.commitWrite()
}
}
}
//...
在同一个回调方法didFinishDownloadingTo
中(最后) - 如果尚未完成完整的文件下载(例如,通过大块文件的块下载,则会启动另一个下载任务)。 ..)。因此,一次又一次地调用回调方法didFinishDownloadingTo
!并且对于每次调用 - 我的Realm对象应保持持久 - 添加列表元素......
// ... the end of the didFinishDownloadingTo callback-method....
if !allFileChunksDownloaded() {
self.downloadService.startDownload(file: file, bytesRange: byteRangeString)
}
}
这就是三个领域对象的样子:
class DownloaderTitleSet: Object {
@objc dynamic var title: String = ""
@objc dynamic var version: String = ""
@objc dynamic var lastItemIndex: Int = 0
var downloaderItems = List<DownloaderItem>()
override static func primaryKey() -> String? {
return "title"
}
}
class DownloaderItem: Object {
@objc dynamic var identifier: String = ""
@objc dynamic var somePoperty: String = ""
@objc dynamic var file: DBFile?
override static func primaryKey() -> String? {
return "identifier"
}
}
class DBFile: Object {
@objc dynamic var index: Int = 0
@objc dynamic var moreProp: Int = 0
override static func primaryKey() -> String? {
return "index"
}
}
我怎样才能做得更好?
-----有问题的后台任务是一个URLSession-DownloadTask,显示的委托方法来自URLSessionDownloadDelegate
回调。
以下代码与RealmSwift-Problem真的无关,我想,但对于对整个图片感兴趣的人 - 这里调用了执行的URLSessionDownload-Task,最终会调用callback-method
// download-Service method starting the background-downloadTask
class MyDownloadService {
var downloadsSession: URLSession!
func startDownload(file: MyFile, bytesRange: String) {
let download = MyDownloadTask(file: file)
var request = URLRequest(url: file.previewURL!)
request.httpMethod = "GET"
request.addValue(file.accountAuthorizationToken!, forHTTPHeaderField: "Authorization")
download.task = self.downloadsSession.downloadTask(with: request)
download.task!.resume()
download.isDownloading = true
self.activeDownloads[download.file.previewURL!] = download
}
}
class MyDownloadTask {
var file: MyFile
init(file: MyFile) {
self.file = file
}
// Download service sets these values:
var task: URLSessionDownloadTask?
var isDownloading = false
var resumeData: Data?
// Download delegate sets this value:
var progress: Float = 0
}