问题描述
我描述的问题。我有一个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.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
}
}
很奇怪,因为如果我评论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属性时,应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!