Realm对象已被删除或失效

时间:2015-08-06 10:03:06

标签: ios swift realm

当我启动应用程序时,我会执行API调用以查看是否有新数据可用。数据存储在我的本地Realm数据库中,其中一些数据显示在初始表视图控制器中。

API调用完成后,我会检查是否满足某些条件,要求我从数据库中删除一堆先前的数据,然后创建新对象。但是,当我删除旧数据时,我的应用程序崩溃时出现以下异常:

2015-08-06 11:56:32.057 MSUapp[19754:172864] *** Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
*** First throw call stack:
(
0   CoreFoundation                      0x000000010660cc65 __exceptionPreprocess + 165
1   libobjc.A.dylib                     0x00000001083bdbb7 objc_exception_throw + 45
2   Realm                               0x0000000105b78e95 _ZL17RLMVerifyAttachedP13RLMObjectBase + 85
3   Realm                               0x0000000105b7878d _ZL10RLMGetLinkP13RLMObjectBasemP8NSString + 29
4   Realm                               0x0000000105b7c23e ___ZL17RLMAccessorGetterP11RLMProperty15RLMAccessorCodeP8NSString_block_invoke_12 + 46
5   MSUapp                              0x0000000105764867 _TFFC6MSUapp29FavoriteLeaguesViewController18generateLeagueListFS0_FT_T_U_FTCS_6LeagueS1__Sb + 39
6   MSUapp                              0x00000001057648eb _TTRXFo_oC6MSUapp6LeagueoS0__dSb_XFo_iS0_iS0__dSb_ + 27
7   libswiftCore.dylib                  0x0000000108674ae2 _TFSs14_insertionSortUSs21MutableCollectionType_USs13GeneratorType__Ss22BidirectionalIndexType_Ss18_SignedIntegerType_Ss33_BuiltinIntegerLiteralConvertible____FTRQ_GVSs5RangeQQ_5Index_RFTQQQ_9Generator7ElementS7__Sb_T_ + 1570
8   libswiftCore.dylib                  0x0000000108676682 _TFSs14_introSortImplUSs21MutableCollectionType_USs13GeneratorType__Ss21RandomAccessIndexType_Ss18_SignedIntegerType_Ss33_BuiltinIntegerLiteralConvertible_Ss16SignedNumberType_S3_____FTRQ_GVSs5RangeQQ_5Index_RFTQQQ_9Generator7ElementS8__SbSi_T_ + 1250
9   libswiftCore.dylib                  0x0000000108676172 _TFSs10_introSortUSs21MutableCollectionType_USs13GeneratorType__Ss21RandomAccessIndexType_Ss18_SignedIntegerType_Ss33_BuiltinIntegerLiteralConvertible_Ss16SignedNumberType_S3_____FTRQ_GVSs5RangeQQ_5Index_FTQQQ_9Generator7ElementS8__Sb_T_ + 1058
10  libswiftCore.dylib                  0x00000001085ec947 _TFSs4sortUSs21MutableCollectionType_USs13GeneratorType__Ss21RandomAccessIndexType_Ss18_SignedIntegerType_Ss33_BuiltinIntegerLiteralConvertible_Ss16SignedNumberType_S3_____FTRQ_FTQQQ_9Generator7ElementS6__Sb_T_ + 471
11  libswiftCore.dylib                  0x00000001086a8d9e _TPA__TFFSa4sortU__FRGSaQ__FFTQ_Q__SbT_U_FRGVSs26UnsafeMutableBufferPointerQ__T_ + 222
12  libswiftCore.dylib                  0x00000001086a8e18 _TPA__TTRG0_R_XFo_lGVSs26UnsafeMutableBufferPointerq___dT__XFo_lGS_q___iT__42 + 56
13  libswiftCore.dylib                  0x00000001085f7fda _TFSa30withUnsafeMutableBufferPointerU__fRGSaQ__U__FFRGVSs26UnsafeMutableBufferPointerQd___Q_Q_ + 522
14  libswiftCore.dylib                  0x00000001085f7db4 _TFSa4sortU__fRGSaQ__FFTQ_Q__SbT_ + 132
15  MSUapp                              0x0000000105761709 _TFC6MSUapp29FavoriteLeaguesViewController18generateLeagueListfS0_FT_T_ + 1097
16  MSUapp                              0x000000010576354b _TFC6MSUapp29FavoriteLeaguesViewController27numberOfSectionsInTableViewfS0_FCSo11UITableViewSi + 59
17  MSUapp                              0x00000001057635fa _TToFC6MSUapp29FavoriteLeaguesViewController27numberOfSectionsInTableViewfS0_FCSo11UITableViewSi + 58
18  UIKit                               0x000000010737cac3 -[UITableViewRowData _updateNumSections] + 84
19  UIKit                               0x000000010737d4b4 -[UITableViewRowData invalidateAllSections] + 69
20  UIKit                               0x00000001071c873b -[UITableView _updateRowData] + 217
21  UIKit                               0x00000001071de2b7 -[UITableView noteNumberOfRowsChanged] + 112
22  UIKit                               0x00000001071dd9f5 -[UITableView reloadData] + 1355
23  MSUapp                              0x00000001057647c6 _TFFC6MSUapp29FavoriteLeaguesViewController11viewDidLoadFS0_FT_T_U_FTO10RealmSwift12NotificationCS1_5Realm_T_ + 166
24  RealmSwift                          0x0000000105f37210 _TFF10RealmSwift41rlmNotificationBlockFromNotificationBlockFFT12notificationOS_12Notification5realmCS_5Realm_T_bTSSCSo8RLMRealm_T_U_FTSSS2__T_ + 224
25  RealmSwift                          0x0000000105f372af _TTRXFo_oSSoCSo8RLMRealm_dT__XFdCb_dCSo8NSStringdS__dT__ + 111
26  Realm                               0x0000000105c0645a -[RLMRealm sendNotifications:] + 986
27  Realm                               0x0000000105c068e6 -[RLMRealm commitWriteTransaction] + 262
28  Realm                               0x0000000105c06a48 -[RLMRealm transactionWithBlock:] + 120
29  RealmSwift                          0x0000000105f34250 _TFC10RealmSwift5Realm5writefS0_FFT_T_T_ + 176
30  MSUapp                              0x00000001056d46db _TZFC6MSUapp14DatabaseHelper23removeForSportAndSeasonfMS0_FTCS_5Sport6seasonSS_T_ + 603
31  MSUapp                              0x0000000105710d22 _TFFFC6MSUapp11AppDelegate14loadRemoteDataFS0_FT_T_U_FGSaCS_5Sport_T_U_FGSaCS_6League_T_ + 866
32  MSUapp                              0x0000000105710dc7 _TTRXFo_oGSaC6MSUapp6League__dT__XFo_iGSaS0___iT__ + 23
33  MSUapp                              0x00000001057103d1 _TPA__TTRXFo_oGSaC6MSUapp6League__dT__XFo_iGSaS0___iT__ + 81
34  MSUapp                              0x000000010575de90 _TTRXFo_iGSaC6MSUapp6League__iT__XFo_oGSaS0___dT__ + 32
35  MSUapp                              0x000000010575ddeb _TFZFC6MSUapp9APIHelper11loadLeaguesFMS0_FTSi18shouldWriteToRealmSb10completionGSqFGSaCS_6League_T___T_U_FCSo6NSDataT_ + 2763
36  MSUapp                              0x00000001056f4a0e _TTSf2n_n_n_n_n_d_i_n_n_n___TFFC6MSUapp14JSONDataSource18loadRemoteJsonDataFS0_FTSSCS_19GETParameterBuilderFCSo6NSDataT__T_U_FTCSo12NSURLRequestGSqCSo17NSHTTPURLResponse_GSqS2__GSqCSo7NSError__T_ + 2302
37  MSUapp                              0x00000001056f2d59 _TPA__TTSf2n_n_n_n_n_d_i_n_n_n___TFFC6MSUapp14JSONDataSource18loadRemoteJsonDataFS0_FTSSCS_19GETParameterBuilderFCSo6NSDataT__T_U_FTCSo12NSURLRequestGSqCSo17NSHTTPURLResponse_GSqS2__GSqCSo7NSError__T_ + 249
38  Alamofire                           0x00000001059e7599 _TTRXFo_oCSo12NSURLRequestoGSqCSo17NSHTTPURLResponse_oGSqCSo6NSData_oGSqCSo7NSError__dT__XFo_oS_oGSqS0__iGSqS1__oGSqS2___dT__ + 25
39  Alamofire                           0x00000001059e7461 _TFFFC9Alamofire7Request8responseFDS0_US_18ResponseSerializer___FT5queueGSqCSo8NSObject_18responseSerializerQ_17completionHandlerFTCSo12NSURLRequestGSqCSo17NSHTTPURLResponse_GSqQ0__GSqCSo7NSError__T__DS0_U_FT_T_U_FT_T_ + 737
40  Alamofire                           0x00000001059e690e _TPA__TFFFC9Alamofire7Request8responseFDS0_US_18ResponseSerializer___FT5queueGSqCSo8NSObject_18responseSerializerQ_17completionHandlerFTCSo12NSURLRequestGSqCSo17NSHTTPURLResponse_GSqQ0__GSqCSo7NSError__T__DS0_U_FT_T_U_FT_T_ + 206
41  Alamofire                           0x00000001059a89d7 _TTRXFo__dT__XFdCb__dT__ + 39
42  libdispatch.dylib                   0x000000010938b186 _dispatch_call_block_and_release + 12
43  libdispatch.dylib                   0x00000001093aa614 _dispatch_client_callout + 8
44  libdispatch.dylib                   0x0000000109392a1c _dispatch_main_queue_callback_4CF + 1664
45  CoreFoundation                      0x00000001065741f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
46  CoreFoundation                      0x0000000106535dcb __CFRunLoopRun + 2043
47  CoreFoundation                      0x0000000106535366 CFRunLoopRunSpecific + 470
48  GraphicsServices                    0x000000010cc17a3e GSEventRunModal + 161
49  UIKit                               0x00000001070f08c0 UIApplicationMain + 1282
50  MSUapp                              0x000000010570f857 main + 135
51  libdyld.dylib                       0x00000001093df145 start + 1
52  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

这个调用堆栈让我假设,这是因为我在FavoriteLeaguesViewController的generateLeagueList方法中的写访问权限。以下是它的正文:

var favorites = FavoritesHelper.sharedInstance.favoriteLeagues
favorites.sort { $0.sport < $1.sport }

for favorite in favorites {
  // Add to array, which we can later use for cellForRowAtIndexPath
}

favorites的类型为[League],其中League是一个Realm对象。我假设发生异常是因为我正在访问League对象的属性,这些对象同时已从Realm数据库中删除(因为已在AppDelegate中启动的API调用现已完成)

我的问题是:我怎样才能防止这种情况发生?如何在删除任何League对象之前确保不再有写入/读取权限?

12 个答案:

答案 0 :(得分:50)

您可以通过调用object.invalidated来检查对象是否已从领域中删除 - 如果它返回true,则它已被删除或领域已手动失效。

答案 1 :(得分:24)

我有一个非常好的方法来捕获Swift中的RLMException。

目前Swift没有显示RLMException发生的位置。

在Realm / RLMUtil.mm:266中,有RLMException的定义。

如果更改代码以生成快速错误,

Xcode现在可以显示异常发生的位置。

现在它是Swift的一部分。

// Realm/RLMUtil.mm:266
static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) {
    // add some code to generate a swift error. E.g. division-by-zero.
    int a = 0;
    if (reason == nil) {
        a = 1;
    }
    NSLog(@"calculating 1 / %d = %f", a, 1 / a);

    ... remainder of the original code...
}

答案 2 :(得分:15)

我只是将断点放在方法中:

// Realm/RLMUtil.mm:193
static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) {
    // ...
}

在左侧面板上,您可以检查堆栈跟踪,在这里您可以找到错误抛出的位置。

答案 3 :(得分:9)

问题发生在我的FavoritesHelper课程中。它同时具有favoriteLeagueIDsfavoriteLeagues属性。我总是设置它们并使用ID作为内部使用,并且只要我想要来自这些联盟的数据,我就会使用其他属性。

这意味着,favoriteLeagues属性(类型[League])经常引用所有喜欢的联赛,因此当我想要在失效后获取它们时会崩溃应用程序。

我为解决这个问题所采取的措施是将属性favoriteLeagues更改为计算属性,如下所示:

var favoriteLeagues: [League] {
    get {
        var leagues = [League]()
        for id in favoriteLeagueIDs {
            if let league = realm.objectForPrimaryKey(League.self, key: id) {
                leagues.append(league)
            }
        }
        return leagues
    }
}

现在联盟不再被引用,只是在需要阅读时才从数据库加载。由于if let语句(Realm.objectForPrimaryKey(:key:)方法在这种情况下返回nil),因此无法加载无效或已删除的对象。

答案 4 :(得分:5)

您可以调用isInvalidatedinvalidated来判断对象是否无效(是)或不是(否)。 您还可以编写一个自定义方法来定义真实的invalidate

查找文档,我们将看到一个属性:

 /**
 Indicates if the object can no longer be accessed because it is now invalid.

 An object can no longer be accessed if the object has been deleted from the Realm that manages it, or
 if `invalidate` is called on that Realm.
 */
@property (nonatomic, readonly, getter = isInvalidated) BOOL invalidated;

invalidated只读,但isInvalidated是什么意思?

等于- (BOOL)invalidated { return invalidated; }

这意味着您可以编写一个自定义方法来定义您想要的真实invalidate

答案 5 :(得分:3)

尝试在域中创建元素,而不是添加

所以:

try! realm.write {
        realm.add(...)
    }

替换为:

try! realm.write {
        realm.create(...)
    }

然后,在执行删除操作后,领域将按预期工作!

答案 6 :(得分:2)

我无法像其他人建议的那样在Realm框架内放置断点,而是在我的整个项目中放置了一个异常断点:

enter image description here

这允许我在抛出异常时捕获正确的堆栈跟踪,并找到我的错误。

答案 7 :(得分:1)

在我的情况下,我一次要从2个表中删除数据。

        let itemToDelete = counters[indexPath.row]
        let realm = try! Realm()
        try! realm.write {
            realm.delete(itemToDelete)
            let predicate = NSPredicate(format: "counterid = \(c.id)")
            let children = realm.objects(Details.self).filter(predicate)
            realm.delete(children)
        }

但是问题是我试图删除不再存在的项的子项。切换顺序,解决了!

        let itemToDelete = counters[indexPath.row]
        let realm = try! Realm()
        try! realm.write {
            let predicate = NSPredicate(format: "counterid = \(c.id)")
            let children = realm.objects(Details.self).filter(predicate)
            realm.delete(children)
            realm.delete(itemToDelete) //this should be deleted after
        }

希望这对其他人有帮助!

答案 8 :(得分:0)

根据我的经验,如果您尝试在删除后使用目标对象(要删除的对象),应用程序将崩溃。

如果要在删除领域对象之后触发某些代码块,只需尝试在将对象删除到内存中之前立即触发该代码块。从内存中删除该对象后尝试使用该对象会造成一些问题,并使应用程序崩溃。

例如:

yield

答案 9 :(得分:0)

您可以做的就是观察从初始Realm查询返回的Results<>对象(用于填充列表/表视图的对象),并在观察者回调方法中更新该列表。数据库。

只需确保使用与初始查询所用的对象相同的Realm实例来删除/修改该对象。

编辑:

一些代码示例:

let realm = Realm()
let results = realm.objects(Favourite.self)
let notificationToken = results.observe { [weak self] (changes) in
    guard let tableView = self?.tableView else { return }
    tableView.reloadData()
}

// Somewhere else
try? realm.write {
    if let favourite = results.first {
         realm.delete(favourite)
    }
}

// OR
if let objectRealm = results.first?.realm {
    try? objectRealm.write {
        objectRealm.delete(results.first!)
    }
}

// Don't forget to stop observing in deinit{}
// notificationToken.invalidate()

答案 10 :(得分:0)

花了一天的时间后,我在DispatchQueue.main.async函数中找出了删除 realm.delete()并最终成功了。

DispatchQueue.main.async {
  realm.delete()
}

realm.delete()

答案 11 :(得分:0)

似乎是使用RxDataSources时的常见问题, 这是一个工作回合,可以防止由于采用IdentifiableType协议而导致崩溃。

检查Realm对象是否无效。如果是这样,只需返回一个随机的唯一值,如下所示:

  var identity: String {
        return isInvalidated ? "deleted-object-\(UUID().uuidString)" : objectId
    }

来源:-https://github.com/RxSwiftCommunity/RxDataSources/issues/172#issuecomment-427675816