本文介绍了核心数据:当访问NSManagedObject属性时,应用程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我描述的问题。我有一个CoreData实体新。我使用一个fetchedResultsController与tableView来呈现对象。问题是当应用程序尝试更新标签时,它崩溃(单元格有两个标签,但app总是在同一句中崩溃,更新相同的标签...)。



一些代码在这里:




  • 这是CoreDataManager的定义:



{

  // MARK: - 共享实例

/ **
*这个类变量提供了一个简单的方法来访问
*到CoreDataStackManager类的共享实例。
* /
class func sharedInstance() - > CoreDataStackManager {

struct Singleton {
static let instance = CoreDataStackManager()
}
return Singleton.instance
}

// MARK: - 核心数据堆栈。代码已从AppDelegate中移动,未更改。
lazy var applicationDocumentsDirectory:NSURL = {

let urls = NSFileManager.defaultManager()。URLsForDirectory(.DocumentDirectory,inDomains:.UserDomainMask)
return urls [urls.count-1 ]
}()

lazy var managedObjectModel:NSManagedObjectModel = {

let modelURL = NSBundle.mainBundle()。URLForResource(Model,withExtension:momd )!
return NSManagedObjectModel(contentsOfURL:modelURL)!
}()

lazy var persistentStoreCoordinator:NSPersistentStoreCoordinator? = {

let coordinator:NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel:self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SQLITE_FILE_NAME)

var failureReason =创建或加载应用程序保存的数据时出错。
do {
try coordinator?.addPersistentStoreWithType(NSSQLiteStoreType,configuration:nil,URL:url,options:nil)
} catch {
//报告任何错误。
var dict = [String:AnyObject]()
dict [NSLocalizedDescriptionKey] =无法初始化应用程序保存的数据
dict [NSLocalizedFailureReasonErrorKey] = failureReason

dict [NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain:YOUR_ERROR_DOMAIN,代码:9999,userInfo:dict)
//用代码替换以正确处理错误。
// abort()导致应用程序生成崩溃日志并终止。您不应在运送应用程序中使用此功能,但在开发过程中可能很有用。
NSLog(Unresolved error \(wrappedError),\(wrappedError.userInfo))
abort()
}

return coordinator
}()

lazy var managedObjectContext:NSManagedObjectContext = {

let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator

return managedObjectContext
}()

// MARK: - 核心数据保存支持
func saveContext(){

if managedObjectContext.hasChanges {

managedObjectContext.performBlockAndWait {
do {
try self.managedObjectContext.save()
} catch {
let nserror = error as NSError
NSLog(未解析的错误\(nserror),\(nserror.userInfo))
abort()
}
}
}




  •   func tableView(tableView:UITableView,cellForRowAtIndexPath indexPath:NSIndexPath) - > UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier(HotNewsCell)as! NewsTableViewCell
    let new = fetchedResultsController.objectAtIndexPath(indexPath)as!新的

    configureCell(cell,new:new)

    return cell
    }

    private func configureCell(cell:NewsTableViewCell,new:新的){

    cell.titleLabel.text = new.title
    / *下一行是应用程序崩溃:( * /
    cell.descriptionLabel.text = new.newBody

    if let url = NSURL(string:new.photoReference){

    cell.activityIndi​​cator.startAnimating()

    if new.image!= nil {
    cell.imageViewNews.image = new.image
    cell.activityIndi​​cator.stopAnimating()
    }
    else {

    let task = NetworkRequests.sharedInstance ().makeImageRequestFromURL(url){(data,error)in

    guard error == nil else {
    print(error)
    return
    }

    guard let data = data else {
    print(No data available)
    return
    }

    let image = UIImage(data:data )
    new.image = image

    dispatch_async(dispatch_get_main_queue())
    {
    cell.imageViewNews.image = image
    cell.activityIndi​​cator.stopAnimating )
    }
    }

    cell.taskToCancelifCellIsReused = task
    }
    }




很奇怪,因为如果我评论cell.descriptionLabel.text = new.newBody p>

谢谢!



EDIT



错误为EXC_BAD_ACCESS。然后,我启用了NSZombie,错误是消息发送到释放实例。

解决方案

我相信这是一个人工制品使用开始 new .... 的属性名称。要避免此问题,只需更改属性的名称。



另请参见到一个无关的问题,突出了 new ... 的问题。从该答案(Clang文档)中确定的,似乎技术上,如果new之后的字符是小写字母,则不会出现问题。所以 newbody 将会正常,而 newBody 则不会。另外,为了完整起见,同样应该避免以下前缀(尽管它们不太可能是属性名称的选择):





  • 复制

  • mutableCopy

  • init



有趣的是,Xcode(至少版本7.3;不确定以前的版本)不会允许这些属性名称在Objective-C,给出一个编译器错误:

很遗憾,Swift编译器不提供任何错误或警告。


I describe the problem. I have an CoreData entity "New". I'm using a fetchedResultsController with a tableView to present the objects. The problem is when app tries to update a label, it crashed (cell has two labels, but app always crashes in the same sentence, updating the same label...).

Some code here:

  • That is the definition of the CoreDataManager:

{

// MARK: - Shared Instance

/**
*  This class variable provides an easy way to get access
*  to a shared instance of the CoreDataStackManager class.
*/
class func sharedInstance() -> CoreDataStackManager {

    struct Singleton {
        static let instance = CoreDataStackManager()
    }
    return Singleton.instance
}

// MARK: - The Core Data stack. The code has been moved, unaltered, from the AppDelegate.
lazy var applicationDocumentsDirectory : NSURL = {

    let urls  = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    return urls[urls.count-1]
}()

lazy var managedObjectModel: NSManagedObjectModel = {

    let modelURL = NSBundle.mainBundle().URLForResource("Model", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {

    let coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent(SQLITE_FILE_NAME)

    var failureReason = "There was an error creating or loading the application's saved data."
    do {
        try coordinator?.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
    } catch {
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason

        dict[NSUnderlyingErrorKey] = error as NSError
        let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this 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 \(wrappedError), \(wrappedError.userInfo)")
        abort()
    }

    return coordinator
}()

lazy var managedObjectContext: NSManagedObjectContext = {

    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator

    return managedObjectContext
}()

// MARK: - Core Data Saving support
func saveContext() {

    if managedObjectContext.hasChanges {

        managedObjectContext.performBlockAndWait {
            do {
                try self.managedObjectContext.save()
            } catch {
                let nserror = error as NSError
                NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
                abort()
            }
        }
    }

  • Here, where the app crashes:

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCellWithIdentifier("HotNewsCell") as! NewsTableViewCell
        let new = fetchedResultsController.objectAtIndexPath(indexPath) as! New
    
        configureCell(cell, new: new)
    
        return cell
    }
    
    private func configureCell(cell: NewsTableViewCell, new: New) {
    
    cell.titleLabel.text = new.title
    /* Next line is where app crashes :( */
    cell.descriptionLabel.text = new.newBody
    
    if let url = NSURL(string: new.photoReference) {
    
        cell.activityIndicator.startAnimating()
    
        if new.image != nil {
            cell.imageViewNews.image = new.image
            cell.activityIndicator.stopAnimating()
        }
        else {
    
            let task = NetworkRequests.sharedInstance().makeImageRequestFromURL(url) { (data, error) in
    
                guard error == nil else {
                    print(error)
                    return
                }
    
                guard let data = data else {
                    print("No data available")
                    return
                }
    
                let image = UIImage(data: data)
                new.image = image
    
                dispatch_async(dispatch_get_main_queue())
                {
                    cell.imageViewNews.image = image
                    cell.activityIndicator.stopAnimating()
                }
            }
    
            cell.taskToCancelifCellIsReused = task
        }
    }
    

It's strange, because if I comment "cell.descriptionLabel.text = new.newBody", app works perfectly.

Thanks!

EDIT

Error was EXC_BAD_ACCESS. Then, I enabled NSZombie, and the error is "message sent to deallocated instance".

解决方案

I believe this is an artefact of using an attribute name which begins new..... To avoid the problem, just change the name of the attribute.

See also this answer to an unrelated question, which highlights the problem with new.... From the document identified in that answer (the Clang documentation), it seems technically the problem would not arise if the character immediately after "new" is a lower case letter. So newbody would be OK, whereas newBody is not. Also, for completeness, the following prefixes should likewise be avoided (though they are unlikely choices for attribute names):

  • alloc
  • copy
  • mutableCopy
  • init

Interestingly, Xcode (at least version 7.3; not sure about previous versions) will not permit these attribute names in Objective-C, giving a compiler error:

Sadly the Swift compiler does not give any error or warning.

这篇关于核心数据:当访问NSManagedObject属性时,应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 13:39