2015-04-03 73 views
3

我有一個領域模型,存儲時間線(我正在製作視頻編輯應用程序),並且相當頻繁地粉碎訪問它的RMArray屬性。該應用程序已發貨,我自己也沒有經歷過,但我的粉絲們經常通知我這次崩潰。這裏是崩潰日誌:領域與RLMException崩潰:對象已被刪除或無效

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 

這裏是RLMProject代碼:

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

有誰有一個想法是什麼錯我的代碼?

回答

5

RLMProject本身是無效的,這將是不可能的檢查videoAssets.invalidatedsoundtracks.invalidated,這就是爲什麼你的堆棧跟蹤顯示未捕獲的異常在RLMGetArray被拋出。

這意味着在您致電setTimeLineModel之前,該對象已從領域中刪除。請在代碼中查找realm.deleteObject(_:)以查看可能發生的情況。

最後,一些一般性的提示,使您的代碼變得更安全,更簡單:

而不是到處RLMRealm.defaultRealm()RLMObject裏面,你應該使用它的realm屬性。這樣,如果您決定在某個時候更改您的領域的位置,您的RLMObject中的代碼將繼續工作。

另外,您可以使用Swift的免費map函數,而不是在RLMArray上創建擴展來添加地圖。

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

非常感謝! – 2015-04-03 18:23:20

+0

使用對象的領域屬性而不是默認領域也可以更容易地使用單獨的測試領域爲該函數編寫測試 – esthepiking 2015-06-26 15:34:09