Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios EXC_坏_访问代码=EXC_ARM_DA_ALIGN_Ios_Swift_Core Data_Exc Bad Access - Fatal编程技术网

Ios EXC_坏_访问代码=EXC_ARM_DA_ALIGN

Ios EXC_坏_访问代码=EXC_ARM_DA_ALIGN,ios,swift,core-data,exc-bad-access,Ios,Swift,Core Data,Exc Bad Access,我已经用3xiPhone5、5s、6、6s和7测试了我的代码 我只在所有iPhone5设备上看到上述错误。不知道这里发生了什么,但5是32位设备这一事实也许是一个线索 我正在从viewcontroller类调用以下方法 func startRecording() { disableControls() CoreDataStack.shared.performForegroundTask { (context) in let sessionInfo = S

我已经用3xiPhone5、5s、6、6s和7测试了我的代码

我只在所有iPhone5设备上看到上述错误。不知道这里发生了什么,但5是32位设备这一事实也许是一个线索

我正在从viewcontroller类调用以下方法

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
和一个模型,其中一个实体有一个string类型的属性。我仍然只在3x iPhone5上遇到同样的错误。5秒、6秒、6秒、7秒都可以正常工作

这意味着问题可能在于
CoreDataStack


Github repo

我将根据您的代码进行一些猜测

me中的老派开发人员被吸引到配置成员
var deviceNumber:Int16=1
。不正确的对齐设置或旧编译器可能会导致下一项的对齐方式错误。您可以尝试将其作为结构中的最后一项

另一个突出的项目是赋值
sessionInfo.deviceNumber=self.config.deviceNumber
。这似乎是将Int16分配给NSNumber,这可能是一个问题。(我假设SessionInfo是一个基于整个代码的NSManagedObject,其初始值设定项采用上下文参数。这意味着所有数字成员都是NSNumbers。)

试着把线路改成

sessionInfo.deviceNumber = NSNumber(int:self.config.deviceNumber)

我还不熟悉iOS 10对核心数据的添加,但据我所知,viewContext是只读的。但viewContext用于在此代码中创建新对象。当您在调试器中到达这一点时,Xcode控制台是否显示更多信息

NSPersistentContainer
是一个核心数据堆栈的设置,对如何使用它有明确的预期。你误用了它
viewContext
为只读,因此请删除
performForegroundTask
saveViewContext
saveViewContextAndWait
。不要更改
视图上下文的合并策略。在
performBackgroundTask
中,只需使用具有相同方法签名的
NSPersistentContainer
的performBackgroundTask即可。不要使用
newBackgroundContext
。如果您使用的是
NSPersistentContainer
,那么您的CoreDataStack几乎什么都不做


如果您想要一个不同于
NSPersistentContainer
设置的自定义堆栈,那么不要使用
NSPersistentContainer
——只需创建自己的堆栈即可。但是,您尝试编写的设置存在重大问题。当写入同时发生时,从背景上下文和viewContext进行写入都会出现重大问题。mergePolicy可以帮助您做到这一点,但最终可能会丢失您认为已保存的信息。您最好学习使用
NSPersistentContainer
设置的堆栈。

有几个人问我是否解决了这个问题,下面是我所做的。这不是一个真正的解决方案,而是一个解决办法。这可能不适合所有人,但对我有用

我所做的就是拆下电线

try! self.persistentContainer.viewContext.setQueryGenerationFrom(.current)

CoreDataStack
中,问题消失了…

感谢您的建议。我试过了,用尽了所有我能想到的方法来解决这个问题,但没有任何效果。我用最少的代码创建了一个新项目来复制这个问题。请参见已编辑的回购链接问题。如果您能看一看,我将不胜感激!两部分你都试过了吗?那NSNumber部分呢?(我编辑了我的答案,加入了一个样本行。)是的,我也尝试了NSNumber。但在这个示例项目中,我删除了所有数字,实体中只有一个字符串属性,而且仍然在发生。在答案的底部添加了另一个想法。不幸的是,控制台中没有进一步的信息。我可能会尝试在背景上下文中创建对象,看看是否有效。。。我测试完后会报告的!谢谢你的建议。你说的有道理,但有一点我不清楚,那就是为什么我不能使用
newBackgroundContext
。我这样做的原因是我想要一个公共上下文来创建多个对象并成批保存以限制I/O。这是禁忌吗?另外,如果你有好的资源,你能给我一些合适使用
nspersistentcainer
的好参考资料吗?分批保存是个好主意。我建议使用
performBackgroundTask
来完成这项任务。与
newBackgroundContext
相比,它有很多优点。首先,它确保代码在正确的线程上执行。其次,它确保不会同时发生两次写入。第三,它明确地期望这些上下文是一次性的——你在你的区块中使用它们,然后不再使用它们。我发现这是一个比有背景背景更好的系统。我有点困惑。如果我使用对
performBackgroundTask
的多个调用创建实体,我如何批量保存?我无法在一个块中创建所有实体,因此我的推理是使用
newBackgroundContext
为每个新实体创建公共上下文。我在这里遗漏了什么?假设您有100个实体,并希望以25个为一批保存它们。调用
performBackgroundTask
4次,每次都会得到一个新的上下文。您可以使用上下文插入25项,然后保存上下文,然后放弃上下文以及指向它的所有指针。如果您有一些需要全部链接到的公共实体(例如,100篇文章都有相同的作者),那么您必须为每个上下文重新蚀刻该实体。github项目缺少CoreDataSt