领域崩溃与RLMException:对象已被删除或无效 [英] Realm crashes with RLMException: object has been deleted or invalidated

查看:2739
本文介绍了领域崩溃与RLMException:对象已被删除或无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个存储时间线的领域模型(我正在制作视频编辑应用程序),并且很频繁地破坏了访问它的RMArray属性。该应用程序已经发货,我没有经历过我自己,但我的crushlytics通知我关于这次崩溃经常。这是崩溃日志:

 致命异常:RLMException 
对象已被删除或无效。

线程:致命异常: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基础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

这是RLMProject代码:

 协议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)

//应该由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
动态var dateCreated:NSDate = NSDate()

动态变量idValue:Int = 0

func setTimeLineModel(timeLine:TimeLineModel,beginWriteTransaction:Bool = true){
func updateArray(array:RLMArray,withAssetsArray assetsArray:[MediaAsset],type:MediaType){
array.removeAllObjects()
为assetsArray {
let model = RLMMediaAsset()
型号.setMediaAsset(asset)
model.setType(type)
array.addObject(model)
RLMRealm.defaultRealm()。addObject(model)
}
}
如果beginWriteTransaction {RLMRealm.defaultRealm()。beginWriteTransaction()}

如果videoAssets.invalidated {videoAssets = RLMArray(objectClassName:RLMMediaAsset.className())}
如果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()
如果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
}
}

扩展名RLMArray {
func map< U>(transform: RLMObject)→U)→> [U] {
var array:[U] = []
对于self中的对象{
array.append(transform(object))
}
返回数组
}
}

有人知道我的代码有什么问题?

解决方案

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() }

这篇关于领域崩溃与RLMException:对象已被删除或无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆