Подтвердить что ты не робот

Объект 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 за это время (потому что вызов API, который был запущен в AppDelegate, теперь завершен).

Тогда мой вопрос: как я могу предотвратить это? Как я могу убедиться, что больше нет записи/чтения-доступа к любому из объектов League до их удаления?

4b9b3361

Ответ 1

Проблема была в моем классе FavoritesHelper. Он имел свойство favoriteLeagueIDs и favoriteLeagues. Я всегда устанавливал их оба и использовал идентификаторы для внутреннего использования и другого свойства, когда мне нужны данные из этих лиг.

Это означало, что все любимые лиги постоянно ссылались на свойство 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 в таком случае).

Ответ 2

Вы можете проверить, был ли объект удален из Realm, вызвав object.invalidated - если он возвращает true, то он был удален или Realm недействителен вручную.

Ответ 3

У меня есть действительно хороший способ поймать RLMException в Swift.

В настоящее время 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...
}

Ответ 4

Я только что поставил точку останова внутри метода:

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

И на левой панели вы можете проверить трассировку стека, здесь вы можете найти, где вызывается ошибка.

Ответ 5

Вы можете позвонить в isInvalidated или invalidated, чтобы определить, что объект недействителен (ДА) или нет (НЕТ). Вы также можете написать собственный метод, чтобы определить, что реально 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.

Ответ 6

Попробуйте создать элемент в области вместо добавить

Итак:

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

Заменить на:

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

А затем после операции удаления область должна работать как положено!

Ответ 7

Мне не удалось разместить точки останова в рамках Realm, как и другие, но вместо этого поставил точку останова исключения для всего моего проекта:

введите описание изображения здесь

Это позволило мне поймать правильную трассировку стека при выбросе исключения и найти ошибку.

Ответ 8

потратив день, я выяснил, как удалить remove DispatchQueue.main.async в моей функции realm.delete(), и, наконец, это сработало.

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

-

realm.delete()

Ответ 9

По моему опыту, если вы попытаетесь использовать целевой объект (который вы хотите удалить) после удаления, приложение будет аварийно завершено.

Если вы хотите вызвать некоторые блоки кода после удаления объекта области, просто попытайтесь запустить этот блок непосредственно перед удалением объекта в памяти. Попытка использовать этот объект после удаления из памяти создаст некоторые проблемы и приведет к сбою приложения.

Например:

    try! realm.write {
        print("deleted word: \(targetObject.word)")
        realm.delete(targetObject)

        //  targetObject was removed, so don't try to access it otherwise you gonna got the 'nil' value instead of object.
    }

Ответ 10

Что вы можете сделать, так это наблюдать объект Results<>, возвращенный из исходного запроса Realm (тот, который использовался для заполнения вашего списка/представления таблицы), и обновлять этот список в методе обратного вызова наблюдателя при каждом изменении в базе данных.

Просто убедитесь, что вы используете тот же экземпляр Realm для удаления/изменения объекта, который использовался для первоначального запроса.

EDIT:

Некоторые примеры кода:

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

Ответ 11

В моем случае я удалял данные из 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
        }

Надеюсь, это поможет кому-то еще!