EXC_BAD_ACCESS代码=EXC_ARM_DA_ALIGN
EXC_BAD_ACCESS code=EXC_ARM_DA_ALIGN
我用 3 x iPhone 5、5、6、6 和 7 测试了我的代码。
我只在所有 iPhone 5 台设备上收到上述错误。不知道这里发生了什么,但也许 5 是 32 位设备这一事实可能是一个线索?
我正在从 viewcontroller class
中调用以下方法
func startRecording() {
disableControls()
CoreDataStack.shared.performForegroundTask { (context) in
let sessionInfo = SessionInfo(context: context)
sessionInfo.startTime = Date().timeIntervalSince1970
sessionInfo.userId = self.config.userId
sessionInfo.devicePosition = self.config.devicePosition.rawValue
sessionInfo.deviceType = self.config.deviceType.rawValue
sessionInfo.deviceNumber = self.config.deviceNumber
sessionInfo.deviceSide = self.config.deviceSide.rawValue
do {
try context.obtainPermanentIDs(for: [sessionInfo])
} catch {
print("Error obtaining permanent ID for session info record")
return
}
CoreDataStack.shared.saveViewContextAndWait()
DispatchQueue.main.async {
guard sessionInfo.objectID.isTemporaryID == false else {
print("ObjectID is temporary")
return
}
self.recording = true
self.statusLabel.text = "Recording..."
self.recordManager.start(sessionUID: sessionInfo.uid)
}
}
}
配置变量是一个简单的结构:
struct Configuration {
var userId: String = "Unknown"
var deviceType: DeviceType = .phone // enum: String
var deviceSide: DeviceSide = .notApplicable // enum: String
var deviceNumber: Int16 = 1
var devicePosition: DevicePosition = .waist // enum: String
}
CoreDataStack 在这里:
final class CoreDataStack {
static let shared = CoreDataStack()
private init() {}
var errorHandler: (Error) -> Void = { error in
log.error("\(error), \(error._userInfo)")
}
private struct constants {
static let persistentStoreName = "Model"
}
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: constants.persistentStoreName)
container.loadPersistentStores(completionHandler: { [weak self] (storeDescription, error) in
if let error = error {
self?.errorHandler(error)
}
})
return container
}()
lazy var viewContext: NSManagedObjectContext = {
self.persistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current)
return self.persistentContainer.viewContext
}()
private lazy var backgroundContext: NSManagedObjectContext = {
let context = self.persistentContainer.newBackgroundContext()
context.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump
return context
}()
func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
self.viewContext.performAndWait {
block(self.viewContext)
}
}
func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
backgroundContext.perform {
block(self.backgroundContext)
}
}
func saveBackgroundContext() {
viewContext.performAndWait {
do {
if self.viewContext.hasChanges {
try self.viewContext.save()
}
} catch {
self.errorHandler(error)
}
self.backgroundContext.perform {
do {
if self.backgroundContext.hasChanges {
try self.backgroundContext.save()
self.backgroundContext.refreshAllObjects()
}
} catch {
self.errorHandler(error)
}
}
}
}
func saveViewContext() {
viewContext.perform {
if self.viewContext.hasChanges {
do {
try self.viewContext.save()
} catch {
self.errorHandler(error)
}
}
}
}
func saveViewContextAndWait() {
viewContext.performAndWait {
if self.viewContext.hasChanges {
do {
try self.viewContext.save()
} catch {
self.errorHandler(error)
}
}
}
}
}
代码在 startRecording
方法中的以下行被轰炸:
try context.obtainPermanentIDs(for: [sessionInfo])
编辑:
我创建了一个精简的测试应用程序,仅包含 CoreDataStack
和一个模型,该模型具有一个实体和一个字符串类型的属性。我仍然在 3x iPhone 5 上遇到同样的错误。 5s、6、6s、7 都可以。
这意味着问题出在 CoreDataStack
上?
Github 回购 here
我将根据对您的代码的简短浏览进行一些猜测。
我这个老派开发人员被配置成员所吸引 var deviceNumber: Int16 = 1
。不正确的对齐设置或旧的编译器可能会导致下一项对齐错误。您可以尝试将其设为结构中的最后一项。
另一个突出的项目是作业sessionInfo.deviceNumber = self.config.deviceNumber
。这看起来是将 Int16 分配给 NSNumber,这可能是个问题。 (我假设 SessionInfo 是一个基于整体代码的 NSManagedObject,它的初始值设定项采用上下文参数。这意味着所有数字成员都是 NSNumbers。)
尝试将行更改为
sessionInfo.deviceNumber = NSNumber(int:self.config.deviceNumber)
我还不熟悉 Core Data 的 iOS 10 个新增内容,但从我正在阅读的内容来看,viewContext 是只读的。但是 viewContext 被用来在这段代码中创建一个新对象。当您在调试器中到达这一点时,Xcode 控制台是否显示更多信息?
NSPersistentContainer
是一个核心数据堆栈的设置,对如何使用它有明确的期望。你在滥用它。 viewContext
是只读的,因此删除 performForegroundTask
、saveViewContext
和 saveViewContextAndWait
。不要更改 viewContext
的 mergePolicy。在 performBackgroundTask
中,只需使用具有相同方法签名的 NSPersistentContainer
的 performBackgroundTask。不要使用 newBackgroundContext
。如果您正在使用 NSPersistentContainer
,您的 CoreDataStack 应该几乎什么都不做。
如果您想要一个不同于 NSPersistentContainer
设置的自定义堆栈,请不要使用 NSPersistentContainer
- 只需创建您自己的堆栈。但是您尝试编写的设置存在重大问题。当写入同时发生时,从后台上下文和 viewContext 写入有 主要 问题。 mergePolicy 可以提供帮助,但您最终可能会丢失您认为已保存的信息。你最好学习使用 NSPersistentContainer
设置的堆栈。
有几个人问我是否解决了这个问题,所以这就是我所做的。这不是真正的解决方案,而是更多的解决方法。它可能不适合所有人,但对我有用。
我所做的只是删除了行
try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current)
来自 CoreDataStack
,问题消失了...
我用 3 x iPhone 5、5、6、6 和 7 测试了我的代码。
我只在所有 iPhone 5 台设备上收到上述错误。不知道这里发生了什么,但也许 5 是 32 位设备这一事实可能是一个线索?
我正在从 viewcontroller class
中调用以下方法func startRecording() {
disableControls()
CoreDataStack.shared.performForegroundTask { (context) in
let sessionInfo = SessionInfo(context: context)
sessionInfo.startTime = Date().timeIntervalSince1970
sessionInfo.userId = self.config.userId
sessionInfo.devicePosition = self.config.devicePosition.rawValue
sessionInfo.deviceType = self.config.deviceType.rawValue
sessionInfo.deviceNumber = self.config.deviceNumber
sessionInfo.deviceSide = self.config.deviceSide.rawValue
do {
try context.obtainPermanentIDs(for: [sessionInfo])
} catch {
print("Error obtaining permanent ID for session info record")
return
}
CoreDataStack.shared.saveViewContextAndWait()
DispatchQueue.main.async {
guard sessionInfo.objectID.isTemporaryID == false else {
print("ObjectID is temporary")
return
}
self.recording = true
self.statusLabel.text = "Recording..."
self.recordManager.start(sessionUID: sessionInfo.uid)
}
}
}
配置变量是一个简单的结构:
struct Configuration {
var userId: String = "Unknown"
var deviceType: DeviceType = .phone // enum: String
var deviceSide: DeviceSide = .notApplicable // enum: String
var deviceNumber: Int16 = 1
var devicePosition: DevicePosition = .waist // enum: String
}
CoreDataStack 在这里:
final class CoreDataStack {
static let shared = CoreDataStack()
private init() {}
var errorHandler: (Error) -> Void = { error in
log.error("\(error), \(error._userInfo)")
}
private struct constants {
static let persistentStoreName = "Model"
}
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: constants.persistentStoreName)
container.loadPersistentStores(completionHandler: { [weak self] (storeDescription, error) in
if let error = error {
self?.errorHandler(error)
}
})
return container
}()
lazy var viewContext: NSManagedObjectContext = {
self.persistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current)
return self.persistentContainer.viewContext
}()
private lazy var backgroundContext: NSManagedObjectContext = {
let context = self.persistentContainer.newBackgroundContext()
context.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump
return context
}()
func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
self.viewContext.performAndWait {
block(self.viewContext)
}
}
func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
backgroundContext.perform {
block(self.backgroundContext)
}
}
func saveBackgroundContext() {
viewContext.performAndWait {
do {
if self.viewContext.hasChanges {
try self.viewContext.save()
}
} catch {
self.errorHandler(error)
}
self.backgroundContext.perform {
do {
if self.backgroundContext.hasChanges {
try self.backgroundContext.save()
self.backgroundContext.refreshAllObjects()
}
} catch {
self.errorHandler(error)
}
}
}
}
func saveViewContext() {
viewContext.perform {
if self.viewContext.hasChanges {
do {
try self.viewContext.save()
} catch {
self.errorHandler(error)
}
}
}
}
func saveViewContextAndWait() {
viewContext.performAndWait {
if self.viewContext.hasChanges {
do {
try self.viewContext.save()
} catch {
self.errorHandler(error)
}
}
}
}
}
代码在 startRecording
方法中的以下行被轰炸:
try context.obtainPermanentIDs(for: [sessionInfo])
编辑:
我创建了一个精简的测试应用程序,仅包含 CoreDataStack
和一个模型,该模型具有一个实体和一个字符串类型的属性。我仍然在 3x iPhone 5 上遇到同样的错误。 5s、6、6s、7 都可以。
这意味着问题出在 CoreDataStack
上?
Github 回购 here
我将根据对您的代码的简短浏览进行一些猜测。
我这个老派开发人员被配置成员所吸引 var deviceNumber: Int16 = 1
。不正确的对齐设置或旧的编译器可能会导致下一项对齐错误。您可以尝试将其设为结构中的最后一项。
另一个突出的项目是作业sessionInfo.deviceNumber = self.config.deviceNumber
。这看起来是将 Int16 分配给 NSNumber,这可能是个问题。 (我假设 SessionInfo 是一个基于整体代码的 NSManagedObject,它的初始值设定项采用上下文参数。这意味着所有数字成员都是 NSNumbers。)
尝试将行更改为
sessionInfo.deviceNumber = NSNumber(int:self.config.deviceNumber)
我还不熟悉 Core Data 的 iOS 10 个新增内容,但从我正在阅读的内容来看,viewContext 是只读的。但是 viewContext 被用来在这段代码中创建一个新对象。当您在调试器中到达这一点时,Xcode 控制台是否显示更多信息?
NSPersistentContainer
是一个核心数据堆栈的设置,对如何使用它有明确的期望。你在滥用它。 viewContext
是只读的,因此删除 performForegroundTask
、saveViewContext
和 saveViewContextAndWait
。不要更改 viewContext
的 mergePolicy。在 performBackgroundTask
中,只需使用具有相同方法签名的 NSPersistentContainer
的 performBackgroundTask。不要使用 newBackgroundContext
。如果您正在使用 NSPersistentContainer
,您的 CoreDataStack 应该几乎什么都不做。
如果您想要一个不同于 NSPersistentContainer
设置的自定义堆栈,请不要使用 NSPersistentContainer
- 只需创建您自己的堆栈。但是您尝试编写的设置存在重大问题。当写入同时发生时,从后台上下文和 viewContext 写入有 主要 问题。 mergePolicy 可以提供帮助,但您最终可能会丢失您认为已保存的信息。你最好学习使用 NSPersistentContainer
设置的堆栈。
有几个人问我是否解决了这个问题,所以这就是我所做的。这不是真正的解决方案,而是更多的解决方法。它可能不适合所有人,但对我有用。
我所做的只是删除了行
try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current)
来自 CoreDataStack
,问题消失了...