且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

领域崩溃与RLMException:对象已被删除或无效

更新时间:2023-12-05 11:10:52

RLMProject 本身无效时,可以检查 videoAssets.invalidated soundtracks.invalidated ,这就是为什么你的堆栈跟踪显示一个未捕获的异常被引入 RLMGetArray



这意味着该对象在您调用 setTimeLineModel 。请在您的代码中查找 realm.deleteObject(_:)以查看可能发生的情况。



最后,一些一般的提示,使您的代码更安全和更简单:



而不是 RLMRealm.defaultRealm()您的 RLMObject 内的任何地方,您应该使用其领域属性。这样,如果您决定在某个时候更改您的领域位置,您的 RLMObject 中的代码将继续运行。



另外,而不是在 RLMArray 上创建扩展名来添加地图,您可以使用Swift的免费地图功能。

  map(videoAssets){($ 0 as RLMMediaAsset).getMediaAsset()} 


I have a realm model that stores time line (i am making video editing app) and quite frequently it crushes on accessing it's RMArray property. The app is already shipped and I haven't experienced it myself but my crushlytics notifies me about this crash quite oftenly. Here is the 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 is the RLMProject code:

protocol IProject{
   var name: String { get set }
   var filterID: Int { get set }
   var filterIntensity: CGFloat { get set }

   /// duration in seconds
   var duration: Int { get set }
   var dateCreated: NSDate { get }

   func setTimeLineModel(timeLine: TimeLineModel, beginWriteTransaction: Bool)

   //    should be done by ProjectImporter
   func getTimeLineModel() -> TimeLineModel

   var videoAssets: RLMArray { get }
   var soundtracks: RLMArray { get }       
}

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()
         for 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 as RLMMediaAsset).getMediaAsset() }
      timeLine.soundtracks = soundtracks.map { ($0 as RLMMediaAsset).getMediaAsset() }

      return timeLine
   }
}

extension RLMArray {   
    func map<U>(transform: (RLMObject) -> U) -> [U]{
        var array: [U] = []
        for object in self{
            array.append(transform(object))
        }
        return array
    }
}

Does anybody has an idea what is wrong with my code?

When the RLMProject itself is invalidated, it won't be possible to check for videoAssets.invalidated or soundtracks.invalidated, which is why your stack trace shows that an uncaught exception is being thrown in RLMGetArray.

This implies that the object has been deleted from the realm before you call setTimeLineModel. Please look for realm.deleteObject(_:) in your code to see where this might be happening.

Finally, a few general tips to make your code a little safer and simpler:

Instead of RLMRealm.defaultRealm() everywhere inside your RLMObject, you should use its realm property. This way, if you decide to change the location of your realm at some point, your code inside your RLMObject will continue to work.

Also, rather than create an extension on RLMArray to add map, you could use Swift's free map function.

map(videoAssets) { ($0 as RLMMediaAsset).getMediaAsset() }