简体   繁体   中英

Core Data: app crashed when accesing to NSManagedObject attribute

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:

Property follows Cocoa naming convention for returning 'owned' objects

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM