gpt4 book ai didi

ios - CoreData 并发问题

转载 作者:行者123 更新时间:2023-11-28 12:47:23 26 4
gpt4 key购买 nike

我在使用 private managedObjectContext 在后台保存数据时遇到问题。我是 CoreData 的新手。我对 NSManagedObjectContext 使用父子方法,但面临几个问题。

多次点击重新加载按钮时出现错误

错误:

  1. 'NSGenericException', reason: Collection <__NSCFSet: 0x16e47100> was mutated while being enumerated

  2. Some times : crash here try managedObjectContext.save()

  3. Sometimes Key value coding Compliant error

我的 ViewController 类

        class ViewController: UIViewController {
var jsonObj:NSDictionary?
var values = [AnyObject]()
@IBOutlet weak var tableView:UITableView!

override func viewDidLoad() {
super.viewDidLoad()
getData()
saveInBD()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.saved(_:)), name: "kContextSavedNotification", object: nil)
}
//Loding json data from a json file

func getData(){
if let path = NSBundle.mainBundle().pathForResource("countries", ofType: "json") {
do {
let data = try NSData(contentsOfURL: NSURL(fileURLWithPath: path), options: NSDataReadingOptions.DataReadingMappedIfSafe)


do {
jsonObj = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary

} catch {
jsonObj = nil;
}


} catch let error as NSError {
print(error.localizedDescription)
}
} else {
print("Invalid filename/path.")
}
}
**Notification reciever**

func saved(not:NSNotification){
dispatch_async(dispatch_get_main_queue()) {
if let data = DatabaseManager.sharedInstance.getAllNews(){
self.values = data
print(data.count)
self.tableView.reloadData()

}

}
}

func saveInBD(){
if jsonObj != nil {
guard let nameArray = jsonObj?["data#"] as? NSArray else{return}
DatabaseManager.sharedInstance.addNewsInBackGround(nameArray)
}
}
//UIButton for re-saving data again

@IBAction func reloadAxn(sender: UIButton) {
saveInBD()
}

}


**Database Manager Class**

public class DatabaseManager{

static let sharedInstance = DatabaseManager()

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

private init() {
}

func addNewsInBackGround(arr:NSArray) {
let jsonArray = arr
let moc = managedObjectContext

let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc

privateMOC.performBlock {
for jsonObject in jsonArray {
let entity = NSEntityDescription.entityForName("Country",
inManagedObjectContext:privateMOC)

let managedObject = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: privateMOC) as! Country

managedObject.name = jsonObject.objectForKey("name")as? String

}


do {
try privateMOC.save()

self.saveMainContext()

NSNotificationCenter.defaultCenter().postNotificationName("kContextSavedNotification", object: nil)
} catch {
fatalError("Failure to save context: \(error)")
}
}

}





func getAllNews()->([AnyObject]?){
let fetchRequest = NSFetchRequest(entityName: "Country")
fetchRequest.resultType = NSFetchRequestResultType.DictionaryResultType

do {
let results =
try managedObjectContext.executeFetchRequest(fetchRequest)
results as? [NSDictionary]
if results.count > 0
{
return results
}else
{
return nil
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
return nil
}
}

func saveMainContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
print("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}

最佳答案

可以在后台写入并在主线程中读取(像您一样使用不同的 MOC)。实际上,您几乎做对了。

应用程序在 try managedObjectContext.save() 行崩溃,因为 saveMainContext 是从私有(private) MOC 的 performBlock 中调用的。修复它的最简单方法是将保存操作包装到另一个 performBlock 中:

func saveMainContext () {
managedObjectContext.performBlock {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
print("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}

另外两个错误有点棘手。请提供更多信息。什么对象不符合什么键的键值?这很可能是 JSON 解析问题。

第一个错误(“枚举时发生突变”)实际上是一个严重的错误。描述非常简单:一个集合在另一个线程上被枚举时被一个线程改变。它发生在哪里?一个可能的原因(我认为最有可能的原因)是它确实是一个 Core Data 多线程问题。尽管您可以使用多个线程,但您只能在获取它们的线程中使用核心数据对象。如果将它们传递给另一个线程,您可能会遇到这样的错误。

查看您的代码并尝试找到可能发生这种情况的地方(例如,您是否从其他类访问 self.values?)。不幸的是,我没能在几分钟内找到这样的地方。如果你说这个错误发生在哪个集合枚举上,那将会有所帮助。

更新:附言我只是认为错误可能与 saveMainContext 函数有关。它在调用 saved 之前执行。 saveMainContext 在后台线程上执行(在原始代码中,我的意思是),而 saved 在主线程上执行。所以在修复 saveMainContext 之后,错误可能会消失(不过我不是 100% 确定)。

关于ios - CoreData 并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37587423/

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