gpt4 book ai didi

ios - swift Realm : Thread Safe Concurrent Read and Write Index out of bounds

转载 作者:行者123 更新时间:2023-11-30 10:51:33 26 4
gpt4 key购买 nike

我正在尝试在 Realm 数据库上安全地进行并发读写。这就是我想要实现的目标。

我正在从 Flickr 中提取图像,下载完 imageData 后,Photo 对象就会写入 Realm 数据库中。我还添加了一个通知来监听插入。将 Photo 对象写入 Realm 后,更新同一项目的 transport 属性。然而,我的实现偶尔会崩溃,即每实现3-5次就会崩溃一次。

代码如下:

override func viewDidLoad() {
super.viewDidLoad()

subscribeToRealmNotifications()
}

fileprivate func subscribeToRealmNotifications() {
do {
let realm = try Realm()
let results = realm.objects(Photo.self)

token = results.observe({ (changes) in
switch changes {
case .initial:
self.setupInitialData()
self.collectionView.reloadData()

case .update(_, _, let insertions, _):
if !insertions.isEmpty {
self.handleInsertionsWhenNotified(insertions: insertions)
}

case .error(let error):
self.handleError(error as NSError)
}
})

} catch let error {
NSLog("Error subscribing to Realm Notifications: %@", error.localizedDescription)
}
}

fileprivate func handleInsertionsWhenNotified(insertions: [Int]) {
let lock = NSLock()
let queue = DispatchQueue(label: "queue", qos: .userInitiated) //Serial queue

queue.async(flags: .barrier) {
do {
let realm = try Realm()
let objects = realm.objects(Photo.self)

lock.lock()
for insertion in insertions {
print(insertion, objects.count, objects[insertion].id ?? "")
let photo = objects[insertion] //Crash here
self.update(photo: photo)
}

lock.unlock()

} catch let error {
NSLog("Error updating photos in Realm Notifications", error.localizedDescription)
}
}
}

func update(photo: Photo) {
do {
let realm = try Realm()
let updatedPhoto = createCopy(photo: photo)

let transport = Transport()
transport.name = searchText
updatedPhoto.transport = transport

try realm.write {
realm.add(updatedPhoto, update: true)
}
} catch let error {
NSLog("Error updating photo name on realm: %@", error.localizedDescription)
}
}

func createCopy(photo: Photo) -> Photo {
let copiedPhoto = Photo()
copiedPhoto.id = photo.id
copiedPhoto.farm = photo.farm
copiedPhoto.server = photo.server
copiedPhoto.secret = photo.secret
copiedPhoto.imageData = photo.imageData
copiedPhoto.name = photo.name
return copiedPhoto
}

//On push of a button, call fetchPhotos to download images.
fileprivate func fetchPhotos() {
FlickrClient.shared.getPhotoListWithText(searchText, completion: { [weak self] (photos, error) in
self?.handleError(error)

guard let photos = photos else {return}

let queue = DispatchQueue(label: "queue1", qos: .userInitiated , attributes: .concurrent)

queue.async {
for (index, _) in photos.enumerated() {
FlickrClient.shared.downloadImageData(photos[index], { (data, error) in
self?.handleError(error)

if let data = data {
let photo = photos[index]
photo.imageData = data
self?.savePhotoToRealm(photo: photo)

DispatchQueue.main.async {
self?.photosArray.append(photo)

if let count = self?.photosArray.count {
let indexPath = IndexPath(item: count - 1, section: 0)
self?.collectionView.insertItems(at: [indexPath])
}
}
}
})
}
}
})
}

fileprivate func savePhotoToRealm(photo: Photo) {
do {
let realm = try Realm()
let realmPhoto = createCopy(photo: photo)

try realm.write {
realm.add(realmPhoto)
print("Successfully saved photo:", photo.id ?? "")
}
} catch let error {
print("Error writing to photo realm: ", error.localizedDescription)
}
}

请注意,上面的代码每 3-5 次就会崩溃一次,因此我怀疑读写操作不安全。崩溃时打印日志和错误日志如图

Successfully saved photo: 45999333945 
4 6 31972639607
6 7 45999333945
Successfully saved photo: 45999333605
Successfully saved photo: 45999333675
7 8 45999333605
8 9 45999333675
Successfully saved photo: 45999333285
Successfully saved photo: 33038412228
2019-01-29 14:46:09.901088+0800 GCDTutorial[24139:841805] *** Terminating app due to uncaught exception 'RLMException', reason: 'Index 9 is out of bounds (must be less than 9).'

有人能帮忙告诉我哪里出了问题吗?

注意:我尝试在 handleInsertionsWhenNotified 处运行 queue.sync。这样做可以完全消除崩溃,但会在主线程上运行时卡住 UI。这对我来说并不理想。

最佳答案

在更仔细地研究日志后,我发现每当应用程序崩溃时,对象计数就不相符。换句话说,当 Realm 通知插入时打印的总对象计数为 9(即使通过浏览器物理检查 Realm 数据库显示超过 9),但插入索引为 9。

这意味着当进行查询时,对象计数可能尚未更新(不太清楚为什么)。阅读了有关 Realm 文档和 here 的更多文章后,我在查询对象之前实现了realm.refresh()。这样问题就解决了。

//Updated code for handleInsertionsWhenNotified
fileprivate func handleInsertionsWhenNotified(insertions: [Int]) {
let lock = NSLock()
let queue = DispatchQueue(label: "queue", qos: .userInitiated) //Serial queue

queue.async(flags: .barrier) {
do {
let realm = try Realm()
realm.refresh() // Call refresh here
let objects = realm.objects(Photo.self)

lock.lock()
for insertion in insertions {
print(insertion, objects.count, objects[insertion].id ?? "")
let photo = objects[insertion] //Crash here
self.update(photo: photo)
}

lock.unlock()

} catch let error {
NSLog("Error updating photos in Realm Notifications", error.localizedDescription)
}
}
}

希望它对任何人都有帮助。

关于ios - swift Realm : Thread Safe Concurrent Read and Write Index out of bounds,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54415510/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com