访问RLMResults的count属性时偶现崩溃问题求助
偶发RLMResults.count崩溃问题分析与临时解决方案
我注意到你在调用RLMResults.count时遇到了偶发性的EXC_BAD_ACCESS崩溃,而且大概率出现在结果集为空的场景——这个问题在Realm社区确实有类似的未解决案例。咱们先梳理清楚问题细节,再给出几个可尝试的临时修复方向:
问题场景复现
你的核心逻辑是通过谓词查询HKCrashObject实例,然后通过结果集的count判断是否需要同步,但崩溃恰好发生在访问results.count的步骤:
-(BOOL)checkIfSyncRequired{ NSPredicate *predicate=[NSPredicate predicateWithFormat:@"self.appLocalEditTimeStamp > self.lastSyncServerTimestamp"]; RLMResults *results = [HKCrashObject objectsWithPredicate:predicate]; if (results.count) {//crash occurs on results.count // 还没执行到这里就崩溃了 return true; }else{ return false; } }
数据模型定义
你的HKCrashObject是基于RLMObject的模型类:
@interface HKCrashObject : RLMObject @property (nonatomic, strong) NSString * customId; @property (nonatomic, assign) long lastSyncServerTimestamp; @property (nonatomic, assign) long appLocalEditTimeStamp; @property (nonatomic, strong) NSString * otherProperties; @end
崩溃堆栈信息
崩溃栈指向Realm底层的数组比较逻辑,属于底层内存访问错误:
(lldb) bt Realm was compiled with optimization - stepping may behave oddly; variables may not be available. * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x000000010ec69f9c Realm`bool realm::Array::compare_leafs_4<realm::Greater, (realm::Action)0, 32ul, bool (*)(long long), 32ul>(realm::Array const*, unsigned long, unsigned long, unsigned long, realm::QueryState<long long>*, bool (*)(long long)) const + 172 frame #1: 0x000000010ec688c8 Realm`bool realm::Array::compare_leafs<realm::Greater, (realm::Action)0, 32ul, bool (*)(long long)>(realm::Array const*, unsigned long, unsigned long, unsigned long, realm::QueryState<long long>*, bool (*)(long long)) const + 504 frame #2: 0x000000010ec68210 Realm`bool realm::Array::compare_leafs<realm::Greater, (realm::Action)0, bool (*)(long long)>(realm::Array const*, unsigned long, unsigned long, unsigned long, realm::QueryState<long long>*, bool (*)(long long)) const + 736 frame #3: 0x000000010ec67b90 Realm`realm::TwoColumnsNode<realm::Column<long long>, realm::Greater>::find_first_local(unsigned long, unsigned long) + 384 frame #4: 0x000000010ecbff93 Realm`realm::ParentNode::aggregate_local(realm::QueryStateBase*, unsigned long, unsigned long, unsigned long, realm::SequentialGetterBase*) + 83 frame #5: 0x000000010ec48a2a Realm`realm::Query::aggregate_internal(realm::Action, realm::DataType, bool, realm::ParentNode*, realm::QueryStateBase*, unsigned long, unsigned long, realm::SequentialGetterBase*) const + 314 frame #6: 0x000000010ec4eb00 Realm`realm::Query::count(unsigned long, unsigned long, unsigned long) const + 480 frame #7: 0x000000010e9c5b2f Realm`realm::Results::size(this=<unavailable>) at results.cpp:136 [opt] * frame #8: 0x000000010ea5b3b0 Realm`::-[RLMResults count]() [inlined] -[RLMResults count]::$_1::operator()() const at RLMResults.mm:137 [opt] frame #9: 0x000000010ea5b3a2 Realm`::-[RLMResults count]() [inlined] auto translateRLMResultsErrors<-[RLMResults count]::$_1>(aggregateMethod=<unavailable>) at RLMResults_Private.hpp:57 [opt] frame #10: 0x000000010ea5b3a2 Realm`::-[RLMResults count](self=<unavailable>, _cmd=<unavailable>) at RLMResults.mm:137 [opt] frame #11: 0x000000010c31842f Jobi`-[myCallsViewController checkIfSyncRequired](self=0x00007fd2b174b990, _cmd="checkIfSyncRequired") at myCallsViewController.m:415 frame #12: 0x000000010c313939 Jobi`-[myCallsViewController viewWillAppear:](self=0x00007fd2b174b990, _cmd="viewWillAppear:", animated=YES) at myCallsViewController.m:85 frame #13: 0x000000010f61cdc0 UIKit`-[UIViewController _setViewAppearState:isAnimating:] + 442 frame #14: 0x000000010f61d62f UIKit`-[UIViewController __viewWillAppear:] + 131 frame #15: 0x000000010f67b9c0 UIKit`-[UITabBarController viewWillAppear:] + 291 frame #16: 0x000000010f61cdc0 UIKit`-[UIViewController _setViewAppearState:isAnimating:] + 442 frame #17: 0x000000010f61d62f UIKit`-[UIViewController __viewWillAppear:] + 131 frame #18: 0x000000010f648d5c UIKit`-[UINavigationController _startCustomTransition:] + 1183 frame #19: 0x000000010f65f5e2 UIKit`-[UINavigationController _startDeferredTransitionIfNeeded:] + 714 frame #20: 0x000000010f6608cc UIKit`-[UINavigationController __viewWillLayoutSubviews] + 150 frame #21: 0x000000010f8b8bd7 UIKit`-[UILayoutContainerView layoutSubviews] + 231 frame #22: 0x000000012c9d761c UIKit`-[UILayoutContainerViewAccessibility layoutSubviews] + 42 frame #23: 0x000000010f542808 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1515 frame #24: 0x000000010e7ec61a QuartzCore`-[CALayer layoutSublayers] + 177 frame #25: 0x000000010e7f082b QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 395
可尝试的临时解决方案
由于这是Realm底层的已知未解决问题,你可以试试以下几种临时修复方式:
- 添加异常捕获:在访问count的代码块外包裹
@try/@catch,避免崩溃直接终止流程:
-(BOOL)checkIfSyncRequired{ NSPredicate *predicate=[NSPredicate predicateWithFormat:@"self.appLocalEditTimeStamp > self.lastSyncServerTimestamp"]; RLMResults *results = [HKCrashObject objectsWithPredicate:predicate]; BOOL needSync = NO; @try { needSync = (results.count > 0); } @catch (NSException *exception) { // 记录异常日志,默认返回不需要同步 NSLog(@"Realm count crash: %@", exception); needSync = NO; } if (needSync) { // 处理结果逻辑 return YES; }else{ return NO; } }
- 转换为NSArray再检查数量:把RLMResults转成NSArray,绕过直接访问RLMResults.count的逻辑:
-(BOOL)checkIfSyncRequired{ NSPredicate *predicate=[NSPredicate predicateWithFormat:@"self.appLocalEditTimeStamp > self.lastSyncServerTimestamp"]; RLMResults *results = [HKCrashObject objectsWithPredicate:predicate]; NSArray *resultsArray = [results array]; if (resultsArray.count) { // 用resultsArray处理逻辑 return YES; }else{ return NO; } }
升级Realm版本:虽然该问题尚未完全解决,但后续版本可能有稳定性修复,尝试更新到最新的Realm Cocoa版本。
后台线程执行查询:如果查询涉及大量数据,把查询操作移到后台线程执行,再回到主线程处理结果,减少主线程的Realm访问冲突。
内容的提问来源于stack exchange,提问作者Er. Khatri
相关产品推荐
相关产品推荐

