在Swift中阅读了关于自定义访问器的this excellent article之后,我从NSDecimalNumber重构为使用新的Decimal类型。我有一个相当复杂的模型,几天来一切都很好,但现在我看到了一个EXC_BAD_ACCESS崩溃,如果我保存托管对象上下文,而必需的(非可选)属性为nil,在我的例子中是baseAmount。在重构之前直接使用NSDecimalNumber时,保存对象会失败,但不会崩溃。
不确定这是否重要,但我正在使用Magic Record的函数保存上下文:NSManagedObjectContext.mr_default().mr_saveToPersistentStoreAndWait()
关于如何修改baseAmount访问器以实现与核心数据相同的失败保存行为以使其不会崩溃,有什么想法吗?
下面是NSManagedObject子类的相关部分,后面是堆栈跟踪:

extension DFTransaction {

    @NSManaged private var primitiveBaseAmount: NSDecimalNumber

    var baseAmount: Decimal {
        get {
            willAccessValue(forKey: "baseAmount")
            defer { didAccessValue(forKey: "baseAmount") }
            return primitiveBaseAmount.decimalValue
        }
        set {
            willChangeValue(forKey: "baseAmount")
            defer { didChangeValue(forKey: "baseAmount") }
            primitiveBaseAmount = NSDecimalNumber(decimal: newValue)
        }
    }
}


[appname]`@objc DFTransaction.baseAmount.getter:
0x100343cd0 <+0>:   stp    x29, x30, [sp, #-16]!
0x100343cd4 <+4>:   mov    x29, sp
0x100343cd8 <+8>:   sub    sp, sp, #96               ; =96
0x100343cdc <+12>:  stur   x0, [x29, #-32]
0x100343ce0 <+16>:  stur   x8, [x29, #-40]
0x100343ce4 <+20>:  bl     0x10051ca64               ; symbol stub for: objc_retain
0x100343ce8 <+24>:  sub    x8, x29, #24              ; =24
0x100343cec <+28>:  ldur   x30, [x29, #-32]
0x100343cf0 <+32>:  str    x0, [sp, #48]
0x100343cf4 <+36>:  mov    x0, x30
0x100343cf8 <+40>:  bl     0x100343da4               ; [appname].DFTransaction.baseAmount.getter : __C.Decimal at DFTransaction.swift:64
0x100343cfc <+44>:  ldur   w9, [x29, #-24]
0x100343d00 <+48>:  ldurh  w10, [x29, #-20]
0x100343d04 <+52>:  ldurh  w11, [x29, #-18]
0x100343d08 <+56>:  ldurh  w12, [x29, #-16]
0x100343d0c <+60>:  ldurh  w13, [x29, #-14]
0x100343d10 <+64>:  ldurh  w14, [x29, #-12]
0x100343d14 <+68>:  ldurh  w15, [x29, #-10]
0x100343d18 <+72>:  ldurh  w16, [x29, #-8]
0x100343d1c <+76>:  ldurh  w17, [x29, #-6]
0x100343d20 <+80>:  ldur   x0, [x29, #-32]
0x100343d24 <+84>:  str    w9, [sp, #44]
0x100343d28 <+88>:  str    w10, [sp, #40]
0x100343d2c <+92>:  str    w11, [sp, #36]
0x100343d30 <+96>:  str    w12, [sp, #32]
0x100343d34 <+100>: str    w13, [sp, #28]
0x100343d38 <+104>: str    w14, [sp, #24]
0x100343d3c <+108>: str    w15, [sp, #20]
0x100343d40 <+112>: str    w16, [sp, #16]
0x100343d44 <+116>: str    w17, [sp, #12]
0x100343d48 <+120>: bl     0x10051ca58               ; symbol stub for: objc_release
0x100343d4c <+124>: ldr    w9, [sp, #44]
0x100343d50 <+128>: ldur   x8, [x29, #-40]
->  0x100343d54 <+132>: str    w9, [x8]    //EXC_BAD_ACCESS
0x100343d58 <+136>: ldr    w10, [sp, #40]
0x100343d5c <+140>: strh   w10, [x8, #4]
0x100343d60 <+144>: ldr    w11, [sp, #36]
0x100343d64 <+148>: strh   w11, [x8, #6]
0x100343d68 <+152>: ldr    w12, [sp, #32]
0x100343d6c <+156>: strh   w12, [x8, #8]
0x100343d70 <+160>: ldr    w13, [sp, #28]
0x100343d74 <+164>: strh   w13, [x8, #10]
0x100343d78 <+168>: ldr    w14, [sp, #24]
0x100343d7c <+172>: strh   w14, [x8, #12]
0x100343d80 <+176>: ldr    w15, [sp, #20]
0x100343d84 <+180>: strh   w15, [x8, #14]
0x100343d88 <+184>: ldr    w16, [sp, #16]
0x100343d8c <+188>: strh   w16, [x8, #16]
0x100343d90 <+192>: ldr    w17, [sp, #12]
0x100343d94 <+196>: strh   w17, [x8, #18]
0x100343d98 <+200>: mov    sp, x29
0x100343d9c <+204>: ldp    x29, x30, [sp], #16
0x100343da0 <+208>: ret

最佳答案

在本文中,我提到“基元访问器总是可以为空的Objective-C引用类型”。这是一个不受等参设置影响的事实,正如您在这些崩溃中发现的那样。
因此,基元访问器的声明必须如下所示:
@NSManaged private var primitiveBaseAmount: NSDecimalNumber?
这样一来,您已经将baseAmount访问器声明为Decimal(非可选),因此当您的自定义get实现遇到一个空的原语值(如return primitiveBaseAmount?.decimalValue ?? 0)时,它必须执行一些非粗糙的操作。

关于ios - 当使用nil required属性保存上下文时,Core Data自定义访问器崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39518655/

10-11 16:56