2016-09-15 2 views
0

После прочтения this excellent article о пользовательских аксессуарах в Swift, я переработал с NSDecimalNumber, чтобы использовать новый тип Decimal. У меня довольно сложная модель, и все работает отлично в течение нескольких дней, но теперь я вижу авария EXC_BAD_ACCESS, если я сохраню контекст управляемого объекта, в то время как требуемое (необязательное) свойство равно nil, baseAmount в моем случае. При непосредственном использовании NSDecimalNumber, перед рефактором сохранение объекта не удастся, но оно не сработает.Сбой при сбое пользовательских аксессуаров Core Data при сохранении контекста с нулевым обязательным атрибутом

Не уверен, если это важно, но я экономлю контекст, используя функцию магических записей в: 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  

ответ

2

В статье я упомянул, что «Примитивные аксессоров всегда обнуляемым Objective-C ссылочные типы». Это правда, на которую не влияет настройка isOptional, поскольку вы находились с этими авариями.

Таким образом, примитивный аксессор должен быть объявлен следующим образом:

@NSManaged private var primitiveBaseAmount: NSDecimalNumber?

С этим из пути, вы объявили аксессор baseAmount быть Decimal (не по желанию), так что ваши custom get реализация должна делать что-то не-crashy, когда оно встречает нулевое примитивное значение, например return primitiveBaseAmount?.decimalValue ?? 0.

+0

Спасибо за ваш быстрый ввод. Я думал, что это может быть так, но я не был уверен, можно ли с этим справиться иначе. – blwinters

+0

На самом деле, я только что внедрил ваши изменения, и я до сих пор вижу тот же самый крах. Я думаю, что это может быть связано с моим использованием MagicalRecord и отсутствием автоматического перехода на объекты Objective-C в Swift 3. Если я не буду это выяснять, я, скорее всего, вернусь к NSDecimalNumber и сделаю с ним. – blwinters

+0

Возможно, проблема связана с тем, что CoreData не любит скалярный аксессуар для 'Decimal', хотя свойство' Decimal' может быть объявлено '@ objc'. В моей статье я рассказываю о том, как объявлять эти аксессоры «не нарушает KVC», но в случае «Decimal» Accessor KVC наиболее определенно нарушен. Возможно, это то, что здесь работает. Объявите свои пользовательские аксессоры как '@nonobjc var baseAmount: Decimal {get {...} set {...}}' и посмотрите, исправляет ли он проблему. –