众所周知系统级崩溃定位不到代码的具体函数,一般都是内存释放时异常,空指针,越界访问问题。再加上苹果应用在切换到后台,杀线程问题,io资源在后台不可以申请问题(当在后台连续断网10分钟,就是定位应用的线程也会被杀掉)。这都是苹果应用一般比安卓应用运行流畅,而开发者对问题定位和线程守护感到头疼的问题。
第一个问题:
h5页面在加载出来前来回多次进入又退出h5页面,导致崩溃。
原因:
第三方库WebViewJavascriptBridgeBase没有进行对是否在主线程进行判断。
修改方案:
if ([NSThread isMainThread]) { [self _evaluateJavascript:javascriptCommand]; } else { dispatch_sync(dispatch_get_main_queue(), ^{ if(javascriptCommand.length == 0) { return; } [self _evaluateJavascript:javascriptCommand]; }); }
第二个问题:
应用启动启动期间,调用了 dispatch_sync回主线程而引起崩溃。注意:app启动时,[NSThread isMainThread]判断是在子线程,也不能会主线程,不然崩溃。
当应用启后,不能在主线程里刷新UI。
方案:
在应用启动后判断是否在主线程,返回主线程。但是在应用启动过程中,禁止使用回主线程。
// this makes sure the change notification happens on the MAIN THREAD if ([NSThread isMainThread]) { } else { dispatch_sync(dispatch_get_main_queue(), ^{ }); }
第三个问题:
在页面控制器中注册了通知,离开页面(不再重用)并期望销毁页面(使用不当导致实际上没有销毁页面,如:常规使用定时器),没有移除通知。当再次申请相同的页面时,有概率性出现通知相关的崩溃。
这个问题是困惑了我们几年的问题,大都报通知事件没有注册。崩溃栈指向的代码都是很正常的代码。这个问题我们最近两个月才发现这个根本原因。若你的技术水平做不到能真正的销毁页面,就在离开页面就移除通知。页面销毁时调用- (void)dealloc函数。只要你使用定时器,不特别处理,就是你把定时器指针置为nil,所在页面也销毁不了。所以实时移除注册的通知很有必要,也最简单。
解决方案:
离开页面就移除通知。若有特别的页面离开后,可能监控通知,自己特别处理,保证它真的不再使用时,在适当时候移除通知。
第四个问题:
在子线程里发送通知,在通知处理函数中不会主线程直接刷新ui引起系统崩溃。
解决方案:
在子线程里发送通知前,判断是否在主线程,若不在主线线程就回主线程,然后再发送通知。这样即好统一管理,实现又简单。
if ([NSThread isMainThread]) { if(self.offLineSuccessBlock != nil) { self.offLineSuccessBlock(YES); } self.hitOnOffLineTime = 0; } else { dispatch_sync(dispatch_get_main_queue(), ^{ if (self.hitOnOffLineTime > 0) { if(self.offLineSuccessBlock != nil) { self.offLineSuccessBlock(YES); } self.hitOnOffLineTime = 0; } }); }
第五个问题:
block为空时返回崩溃问题。
解决方案:
在block处理产生时记录一个时间和block指针。当block返回受限保证这个记录时间有效并且block为非空时再返回。
i
f(self.hitOnOffLineTime > 0) { if(self.offLineSuccessBlock != nil) { if ([NSThread isMainThread]) { if(self.offLineSuccessBlock != nil) { self.offLineSuccessBlock(YES); } self.hitOnOffLineTime = 0; } else { dispatch_sync(dispatch_get_main_queue(), ^{ if (self.hitOnOffLineTime > 0) { if(self.offLineSuccessBlock != nil) { self.offLineSuccessBlock(YES); } self.hitOnOffLineTime = 0; } }); } } else { self.hitOnOffLineTime = 0; } }
第六个问题:
创建一个线程,在这个线程体内开始部分立刻起了一个线程。文件描述符耗尽,引起系统崩溃。
解决方案:
禁止这种无等待连环起线程的错误行为。
第七个问题:
插入一个空对象到可变数组,或初始化数组是的元素为nil.
如下崩溃:
ModalName: 文件日志, ErrorLevel: Error, Function: UncaughtExceptionHandler, Line: 215, Format: <- 2017-03-31 11:02:48 ->[ Uncaught Exception ] Name: NSInvalidArgumentException, Reason: *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0] [ Fe Symbols Start ] 0 CoreFoundation 0x000000018894eff0 <redacted> + 148 1 libobjc.A.dylib 0x00000001873b0538 objc_exception_throw + 56 2 CoreFoundation 0x00000001888302c8 <redacted> + 308 3 CoreFoundation 0x0000000188942c38 <redacted> + 36 4 CoreFoundation 0x0000000188832cbc <redacted> + 36 5 OutdoorClub 0x0000000100133d58 -[ODCCurrentPathLocationDataSingleObject saveCoordateWithFileName:lastLocationOperateModel:] + 308 6 OutdoorClub 0x0000000100132c90 -[ODCCurrentPathLocationDataSingleObject readmis] + 1672 7 OutdoorClub 0x0000000100132324 __50-[ODCCurrentPathLocationDataSingleObject initData]_block_invoke + 100 8 OutdoorClub 0x00000001003c2a10 +[NSTimer(YYAdd) _yy_ExecBlock:] + 148 9 Foundation 0x0000000189443760 __NSFireTimer + 88 10 CoreFoundation 0x00000001888fda9c <redacted> + 28 11 CoreFoundation 0x00000001888fd7a0 <redacted> + 856 12 CoreFoundation 0x00000001888fd060 <redacted> + 244 13 CoreFoundation 0x00000001888fac84 <redacted> + 1484 14 CoreFoundation 0x000000018882ad94 CFRunLoopRunSpecific + 424 15 GraphicsServices 0x000000018a294074 GSEventRunModal + 100 16 UIKit 0x000000018eae3130 UIApplicationMain + 208 17 OutdoorClub 0x000000010014853c main + 124 18 libdyld.dylib 0x000000018783959c <redacted> + 4 [ Fe Symbols End ]
引起崩溃的代码:
这个是上面调用的代码
[self.currentPathLocationDataArray addObject:self.locationOperateModel]; [self saveCoordateWithFileName:ODCCoordatesFileName lastLocationOperateModel:self.currentPathLocationDataArray[self.currentPathLocationDataArray.count-1]];
这个是崩溃的代码。
NSMutableArray *arr = [NSMutableArray arrayWithObject:lastLocationOperateModel];
它是怎么崩溃的呢?因为self.currentPathLocationDataArray为nil,加入的对象,再取出,当然还是nil了,你再初始化数组当然就崩溃了。 修改方法:
if(self.currentPathLocationDataArray == nil) { self.currentPathLocationDataArray = [NSMutableArray array]; } [self.currentPathLocationDataArray addObject:self.locationOperateModel];