アプリを起動するときに、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
オブジェクトのプロパティにアクセスしているため、例外が発生すると仮定します(AppDelegateで開始されたAPI呼び出しが終了したため) )。
私の質問は次のとおりです。これを防ぐにはどうすればよいですか?削除する前に、どのLeague
オブジェクトにも書き込み/読み取りアクセスがないことを確認するにはどうすればよいですか?
問題は私のFavoritesHelper
クラスにありました。 favoriteLeagueIDs
プロパティとfavoriteLeagues
プロパティの両方がありました。私は常に両方を設定し、これらのリーグからのデータが必要なときにはいつでも内部使用と他のプロパティに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
を返します)。
object.invalidated
を呼び出すことにより、オブジェクトがRealmから削除されたかどうかを確認できます。true
を返す場合、オブジェクトが削除されているか、Realmが手動で無効化されています。
Swift内でRLMExceptionをキャッチする本当に素晴らしい方法を手に入れました。
現在SwiftはRLMExceptionが発生した場所を表示しません。
Realm/RLMUtil.mm:266には、RLMExceptionの定義があります。
Swiftエラーを生成するようにコードを変更すると、
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...
}
メソッド内にブレークポイントを配置しました。
// Realm/RLMUtil.mm:193
static NSException *RLMException(NSString *reason, NSDictionary *additionalUserInfo) {
// ...
}
そして、左側のパネルでスタックトレースを確認できます。ここで、エラーがスローされた場所を見つけることができます。
isInvalidated
またはinvalidated
を呼び出して、オブジェクトが無効か(YES)否か(NO)を判断できます。また、実際の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
を定義するカスタムメソッドを作成できます。
addの代わりにcreateレルム上の要素を試してください
そう:
try! realm.write {
realm.add(...)
}
と置換する:
try! realm.write {
realm.create(...)
}
そして、削除操作後、レルムは期待どおりに動作するはずです!
1日を過ごした後、realm.delete()
関数でremoveDispatchQueue.main.async
を見つけて、最終的に機能しました。
DispatchQueue.main.async {
realm.delete()
}
に
realm.delete()
できることは、Results<>
最初のRealmクエリ(リスト/テーブルビューに入力するために使用されるクエリ)から返されたオブジェクト。データベースに変更があるたびに、オブザーバーコールバックメソッドでそのリストを更新します。
最初のクエリで使用したものと同じ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()
私の経験では、削除後にターゲットオブジェクト(削除したい)を使用しようとすると、アプリケーションがクラッシュします。
レルムオブジェクトを削除した後にいくつかのコードブロックをトリガーする場合、オブジェクトがメモリ内で削除される直前にそのブロックをトリガーしようとします。メモリから削除した後にそのオブジェクトを使用しようとすると、問題が発生し、アプリがクラッシュします。
例えば:
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.
}