ios - Realm crashes with RLMException: object has been deleted or invalidated -


i have realm model stores time line (i making video editing app) , quite crushes on accessing it's rmarray property. app shipped , haven't experienced myself crushlytics notifies me crash quite oftenly. here crash log:

fatal exception: rlmexception object has been deleted or invalidated.  thread : fatal exception: rlmexception 0  corefoundation                 0x2614d45f __exceptionpreprocess + 126 1  libobjc.a.dylib                0x3407ec8b objc_exception_throw + 38 2  videoeditor               0x00293919 rlmgetarray(rlmobjectbase*, unsigned int, nsstring*) (rlmrealm_private.hpp:38) 3  videoeditor               0x0018a1b4 videoeditor.rlmproject.settimelinemodel (videoeditor.rlmproject)(videoeditor.timelinemodel, beginwritetransaction : swift.bool) -> () (realmmodels.swift:147) 4  videoeditor               0x0025eb9c videoeditor.videoeditorapi.saveproject (videoeditor.videoeditorapi)(swift.optional<videoeditor.iproject>, timeline : videoeditor.timelinemodel, name : swift.string, filterid : swift.int, image : objectivec.uiimage) -> swift.implicitlyunwrappedoptional<videoeditor.iproject> (videoeditorapi.swift:42) 5  videoeditor               0x00164754 @objc videoeditor.projecteditorviewcontroller.saveproject (videoeditor.projecteditorviewcontroller)(swift.implicitlyunwrappedoptional<objectivec.nsnotification>) -> () (projecteditorviewcontroller.swift:514) 6  corefoundation                 0x26105e31 __cfnotificationcenter_is_calling_out_to_an_observer__ + 12 7  corefoundation                 0x260616cd _cfxnotificationpost + 1784 8  foundation                     0x26db7dd9 -[nsnotificationcenter postnotificationname:object:userinfo:] + 72 9  uikit                          0x296cae2d -[uiapplication _deactivateforreason:notify:] + 528 10 uikit                          0x298d2dd7 -[uiapplication _handlenonlaunchspecificactions:forscene:withtransitioncontext:] + 1846 11 uikit                          0x298caafd -[uiapplication workspace:didreceiveactions:] + 80 12 frontboardservices             0x2ca180a9 __31-[fbsserialqueue performasync:]_block_invoke + 12 13 corefoundation                 0x26113fe5 __cfrunloop_is_calling_out_to_a_block__ + 12 14 corefoundation                 0x261132a9 __cfrunloopdoblocks + 216 15 corefoundation                 0x26111de3 __cfrunlooprun + 1714 16 corefoundation                 0x2605f3b1 cfrunlooprunspecific + 476 17 corefoundation                 0x2605f1c3 cfrunloopruninmode + 106 18 graphicsservices               0x2d5bf201 gseventrunmodal + 136 19 uikit                          0x296c943d uiapplicationmain + 1440 20 merryvideoeditor               0x0028c88f main (main.m:16) 21 libdyld.dylib                  0x3460aaaf start + 2 

here rlmproject code:

protocol iproject{    var name: string { set }    var filterid: int { set }    var filterintensity: cgfloat { set }     /// duration in seconds    var duration: int { set }    var datecreated: nsdate { }     func settimelinemodel(timeline: timelinemodel, beginwritetransaction: bool)     //    should done projectimporter    func gettimelinemodel() -> timelinemodel     var videoassets: rlmarray { }    var soundtracks: rlmarray { }        }  class rlmproject: rlmobject, iproject, printable {    dynamic var videoassets: rlmarray = rlmarray(objectclassname: rlmmediaasset.classname())    dynamic var soundtracks: rlmarray = rlmarray(objectclassname: rlmmediaasset.classname())     dynamic var name: string = ""     dynamic var filterid: int = 0    dynamic var filterintensity: cgfloat = 1     dynamic var duration: int = 0    dynamic var datecreated: nsdate = nsdate()     dynamic var idvalue: int = 0     func settimelinemodel(timeline: timelinemodel, beginwritetransaction: bool = true) {       func updatearray(array: rlmarray, withassetsarray assetsarray: [mediaasset], type: mediatype){          array.removeallobjects()          asset in assetsarray{             let model = rlmmediaasset()             model.setmediaasset(asset)             model.settype(type)             array.addobject(model)             rlmrealm.defaultrealm().addobject(model)          }       }       if beginwritetransaction { rlmrealm.defaultrealm().beginwritetransaction() }        if videoassets.invalidated { videoassets = rlmarray(objectclassname: rlmmediaasset.classname()) }       if soundtracks.invalidated { soundtracks = rlmarray(objectclassname: rlmmediaasset.classname()) }        updatearray(videoassets, withassetsarray: timeline.videoassets, .video)       updatearray(soundtracks, withassetsarray: timeline.soundtracks, .soundtrack)       duration = int(cmtimegetseconds(timeline.totalduration))        datecreated = nsdate()       if beginwritetransaction { rlmrealm.defaultrealm().commitwritetransaction() }    }     func gettimelinemodel() -> timelinemodel {       let timeline = timelinemodel()       timeline.videoassets = videoassets.map { ($0 rlmmediaasset).getmediaasset() }       timeline.soundtracks = soundtracks.map { ($0 rlmmediaasset).getmediaasset() }        return timeline    } }  extension rlmarray {        func map<u>(transform: (rlmobject) -> u) -> [u]{         var array: [u] = []         object in self{             array.append(transform(object))         }         return array     } } 

does has idea wrong code?

when rlmproject invalidated, won't possible check videoassets.invalidated or soundtracks.invalidated, why stack trace shows uncaught exception being thrown in rlmgetarray.

this implies object has been deleted realm before call settimelinemodel. please realm.deleteobject(_:) in code see might happening.

finally, few general tips make code little safer , simpler:

instead of rlmrealm.defaultrealm() everywhere inside rlmobject, should use realm property. way, if decide change location of realm @ point, code inside rlmobject continue work.

also, rather create extension on rlmarray add map, use swift's free map function.

map(videoassets) { ($0 rlmmediaasset).getmediaasset() } 

Comments