在核心数据更改处理期间捕获到异常
Posted
技术标签:
【中文标题】在核心数据更改处理期间捕获到异常【英文标题】:Exception was caught during Core Data change processing 【发布时间】:2015-07-19 16:00:02 【问题描述】:在我的应用程序中,我在AppDelegate
中创建了我的CoreDataStack
,并将该实例传递给我的根视图控制器。在视图控制器中,我连接到一个 API,检索和解析一些 JSON,然后保存到 Core Data。但是,对于大约十分之一的发布,我会立即发生崩溃,这发生在我的 CoreDataStack
类中:
func saveContext ()
if let moc = self.managedObjectContext
var error: NSError? = nil
// This if-statement is the line that gets highlighted following the crash.
if moc.hasChanges && !moc.save(&error)
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
我得到的日志是:
CoreData: error: Serious application error.
Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.
-[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
2015-07-19 11:33:06.115 AppName[210:3907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
在我的视图控制器中,我进入主线程以保存到核心数据。崩溃后,在 Debug Navigator 中浏览堆栈时,self.coreDataStack!.saveContext()
会突出显示。我假设我试图在不同的线程上创建和访问managedObjectContext
,但似乎并非如此,因为当我调用println(NSThread.currentThread()
时,我得到的线程号和名称与打印时相同来自AppDelegate
,我在这里创建了CoreDataStack
实例。
func updateStockInformation(#completion: ((finished: Bool) -> Void)?)
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
if stocks.count > 0
var numberOfStocksUpdated = 0
for stock in stocks
yql.query(stock.symbol, completion: (results) -> Void in
if results != nil
if let query = results!["query"] as? NSDictionary, results = query["results"] as? NSDictionary, quote = results["quote"] as? NSDictionary, lastTradePrice = quote["LastTradePriceOnly"] as? NSString
if let change = quote["Change"] as? NSString
var changeValue = NSDecimalNumber()
if (change as String).hasPrefix("-")
let unsignedNegativeString = change.stringByReplacingOccurrencesOfString("-", withString: "")
let unsignedNegativeNumber = NSDecimalNumber(string: unsignedNegativeString)
let signedNegativeNumber = unsignedNegativeNumber.negative()
changeValue = signedNegativeNumber
else
let unsignedPositiveString = change.stringByReplacingOccurrencesOfString("+", withString: "")
let unsignedPositiveNumber = NSDecimalNumber(string: unsignedPositiveString)
changeValue = unsignedPositiveNumber
if self.market.status == .Open
stock.change = changeValue
var priceValue = NSDecimalNumber()
// Change the 'lastTradePrice' value from an NSString into an NSDecimalNumber
priceValue = NSDecimalNumber(string: lastTradePrice as String)
stock.lastTradePrice = priceValue
stock.profitFromStocksInCompany = self.updateProfitForStock(stock)
numberOfStocksUpdated += 1
if numberOfStocksUpdated == self.stocks.count
dispatch_async(dispatch_get_main_queue(), () -> Void in
println("MainViewController - updateStockInformation: \(NSThread.currentThread())")
println()
self.coreDataStack!.saveContext()
self.updateTotalProfitLabel()
self.reloadPageViewController()
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
self.stockInformationUpdatedDelegate?.stockInformationDidUpdate(self.market.getStatusOfMarket())
completion?(finished: true)
)
)
关于我做错了什么导致偶尔崩溃的任何想法?
【问题讨论】:
【参考方案1】:当我打印出 JSON 数据时,我注意到所有返回的东西都是混乱的,这意味着在接收和解析前一个网络请求的数据之前,for 循环正在快速发送网络请求。所以我决定重组我的代码并使用递归。下面是新改组的代码,它使用递归来更新一只股票的信息,只有在前一只股票的信息被接收、解析和更新后:
func updateStockInformation(#completion: ((finished: Bool) -> Void)?)
updateStock(0, completion: nil)
if stocksUpdatingAppBecameActive
stocksUpdatingAppBecameActive = false
func updateStock(stockIndex: Int, completion: ((finished: Bool) -> Void)?)
var stockIndex = stockIndex
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
if stocks.count > 0
let stock = stocks[stockIndex]
yql.query(stock.symbol, completion: (results) -> Void in
if results != nil
if let query = results!["query"] as? NSDictionary, results = query["results"] as? NSDictionary, quote = results["quote"] as? NSDictionary, lastTradePrice = quote["LastTradePriceOnly"] as? NSString
if let change = quote["Change"] as? NSString
var changeValue = NSDecimalNumber()
// Change the 'change' value from an NSString into an NSDecimalNumber
if (change as String).hasPrefix("-")
let unsignedNegativeString = change.stringByReplacingOccurrencesOfString("-", withString: "")
let unsignedNegativeNumber = NSDecimalNumber(string: unsignedNegativeString)
let signedNegativeNumber = unsignedNegativeNumber.negative()
changeValue = signedNegativeNumber
else
let unsignedPositiveString = change.stringByReplacingOccurrencesOfString("+", withString: "")
let unsignedPositiveNumber = NSDecimalNumber(string: unsignedPositiveString)
changeValue = unsignedPositiveNumber
if self.market.status == .Open
stock.change = changeValue
var priceValue = NSDecimalNumber()
priceValue = NSDecimalNumber(string: lastTradePrice as String)
stock.lastTradePrice = priceValue
stock.profitFromStocksInCompany = self.updateProfitForStock(stock)
self.numberOfStocksUpdated += 1
if self.numberOfStocksUpdated == self.stocks.count
dispatch_async(dispatch_get_main_queue(), () -> Void in
self.coreDataStack!.saveContext()
self.updateTotalProfitLabel()
self.reloadPageViewController()
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
self.stockInformationUpdatedDelegate?.stockInformationDidUpdate(self.market.getStatusOfMarket())
self.numberOfStocksUpdated = 0
completion?(finished: true)
)
else
self.updateStock(stockIndex + 1, completion: nil)
)
【讨论】:
以上是关于在核心数据更改处理期间捕获到异常的主要内容,如果未能解决你的问题,请参考以下文章
CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常
Swift CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。