启动应用程序时,我将执行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方法中具有写访问权限。其主体如下:
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是领域对象。我以为发生异常是因为我正在访问League对象的属性,这些对象的属性已同时从Realm数据库中删除(因为已经在AppDelegate中启动的API调用已完成)。
favorites
[League]
League
那么我的问题是:如何防止这种情况发生?League在删除对象之前,如何确保没有对任何对象的写入/读取权限?
问题在我FavoritesHelper班上。它同时具有favoriteLeagueIDs和favoriteLeagues属性。每当我想要这些联赛的一些数据时,我总是将它们都设置好,并将这些ID用于内部使用,并将另一个属性用于其他用途。
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)。
if let
Realm.objectForPrimaryKey(:key:)
nil