在读取特定的 NSManagedProperty 后释放 NSManagedObject 时,NSPersistentStoreCoordinator 抛出 EXC_BAD_ACCESS
NSPersistentStoreCoordinator throws EXC_BAD_ACCESS when deallocating an NSManagedObject after reading a specific NSManagedProperty
错误描述
我有一个应用程序,其中一些数据使用核心数据(由 SQLite 支持)和以下 NSManagedObject
子类
在本地存储
import CoreData
@objc(ScoutingEventData)
class ScoutingEventData: NSManagedObject {
@NSManaged var id: String?
@NSManaged var type: String?
@NSManaged var entityId: String?
@NSManaged var oldStateJson: NSData?
@NSManaged var newStateJson: NSData?
@NSManaged var eventDate: NSDate?
func toInsertEvent() throws -> ScoutingEvent.Insert {
guard let id = id else { fatalError("events should have an event id") }
guard let data = newStateJson else { fatalError("insert event should have newStateJson stored") }
// If I uncomment this line, the error goes away.
// Somehow by ensuring that data never gets deallocated, the error never occurs.
// globallllll = data
return ScoutingEvent.Insert(id: id, entity: try ScoutingEntity.from(data))
}
}
// debugging var to prevent data from being deallocated
var globallllll: NSData?
如上面代码片段的评论中所述,如果我允许释放从 newStateJson
属性 中读出的值,则会发生错误。
我收到的错误来自后台线程:
如果我在诊断工具中启用僵尸程序,我会得到这个
如果启用僵尸,我还会在控制台中收到以下消息:
2016-11-18 16:26:13.773 ScoutingData_Example[51750:4716636] *** -[CFData release]: message sent to deallocated instance 0x7f8c4eb10ae0
以及以下堆栈跟踪:
到目前为止我已经尝试过什么
我曾尝试将用于获取此数据的 NSManagedObjectContext
存储在静态变量中以确保上下文永远不会被释放,但这没有效果。
我已经尝试将 NSData?
属性转换为 String?
属性,并将数据存储为 Base64 编码字符串而不是二进制数据(并且还更新了支持模型),但是没有效果要么。错误仍然存在。
我尝试注释掉读取 属性 的代码,错误消失了,但这显然不是一个可接受的解决方案。
我曾尝试在读取值后将其存储在全局变量中,以防止它被释放,并且错误消失了,但这也不是一个有效的解决方案。
我已经尝试注释掉所有 使用 值的代码,而是只将值打印到控制台,但错误仍然存在。这让我相信 访问 属性 的行为,然后在稍后释放它,就是为这个错误创造条件的原因。
我很困惑。在我读取数据后我对数据做了什么很重要,这似乎真的很奇怪,而且当它被释放时后台线程上发生的任何事情似乎特别奇怪。
更奇怪的是,它似乎特定于此 属性。例如,我在读取 newDataJson 属性 的行上方读取的 id 属性 不会导致任何问题。你可能认为那是不同的,因为 id 是一个字符串,而不是 NSData,但我尝试将我的 NSData 属性 转换为字符串 属性,但它仍然没有改变错误。
如有任何想法,我们将不胜感激。谢谢。
编辑
不确定这是否有帮助,但这是我的模型架构
给 属性 一个不以 new
开头的名称。我遇到过类似的问题,不得不将 属性 重命名为 theNewState
之类的名称。我认为 new
前缀具有特殊含义并且混淆了 ARC 内存管理。
编辑:参考 Apple ARC release notes,参见 "You cannot give an accessor a name that begins with new." 部分所以它实际上是 accessor/getter 名称,而不是 属性 名称本身。
错误描述
我有一个应用程序,其中一些数据使用核心数据(由 SQLite 支持)和以下 NSManagedObject
子类
import CoreData
@objc(ScoutingEventData)
class ScoutingEventData: NSManagedObject {
@NSManaged var id: String?
@NSManaged var type: String?
@NSManaged var entityId: String?
@NSManaged var oldStateJson: NSData?
@NSManaged var newStateJson: NSData?
@NSManaged var eventDate: NSDate?
func toInsertEvent() throws -> ScoutingEvent.Insert {
guard let id = id else { fatalError("events should have an event id") }
guard let data = newStateJson else { fatalError("insert event should have newStateJson stored") }
// If I uncomment this line, the error goes away.
// Somehow by ensuring that data never gets deallocated, the error never occurs.
// globallllll = data
return ScoutingEvent.Insert(id: id, entity: try ScoutingEntity.from(data))
}
}
// debugging var to prevent data from being deallocated
var globallllll: NSData?
如上面代码片段的评论中所述,如果我允许释放从 newStateJson
属性 中读出的值,则会发生错误。
我收到的错误来自后台线程:
如果我在诊断工具中启用僵尸程序,我会得到这个
如果启用僵尸,我还会在控制台中收到以下消息:
2016-11-18 16:26:13.773 ScoutingData_Example[51750:4716636] *** -[CFData release]: message sent to deallocated instance 0x7f8c4eb10ae0
以及以下堆栈跟踪:
到目前为止我已经尝试过什么
我曾尝试将用于获取此数据的 NSManagedObjectContext
存储在静态变量中以确保上下文永远不会被释放,但这没有效果。
我已经尝试将 NSData?
属性转换为 String?
属性,并将数据存储为 Base64 编码字符串而不是二进制数据(并且还更新了支持模型),但是没有效果要么。错误仍然存在。
我尝试注释掉读取 属性 的代码,错误消失了,但这显然不是一个可接受的解决方案。
我曾尝试在读取值后将其存储在全局变量中,以防止它被释放,并且错误消失了,但这也不是一个有效的解决方案。
我已经尝试注释掉所有 使用 值的代码,而是只将值打印到控制台,但错误仍然存在。这让我相信 访问 属性 的行为,然后在稍后释放它,就是为这个错误创造条件的原因。
我很困惑。在我读取数据后我对数据做了什么很重要,这似乎真的很奇怪,而且当它被释放时后台线程上发生的任何事情似乎特别奇怪。
更奇怪的是,它似乎特定于此 属性。例如,我在读取 newDataJson 属性 的行上方读取的 id 属性 不会导致任何问题。你可能认为那是不同的,因为 id 是一个字符串,而不是 NSData,但我尝试将我的 NSData 属性 转换为字符串 属性,但它仍然没有改变错误。
如有任何想法,我们将不胜感激。谢谢。
编辑
不确定这是否有帮助,但这是我的模型架构
给 属性 一个不以 new
开头的名称。我遇到过类似的问题,不得不将 属性 重命名为 theNewState
之类的名称。我认为 new
前缀具有特殊含义并且混淆了 ARC 内存管理。
编辑:参考 Apple ARC release notes,参见 "You cannot give an accessor a name that begins with new." 部分所以它实际上是 accessor/getter 名称,而不是 属性 名称本身。