FFExtension 1.2.2

FFExtension 1.2.2

kobe1941 维护。



  • hufeng

FFExtension

pod LICENSE weibo status

ARC iOS8.0+

友情链接 996.icu

中文介绍

主要用于降低 iOS APP 的常见崩溃,比如数组字典等容器的越界和插入空值,以及可选的 unrecognized selector sent to instance 这类崩溃。

最新版本已经去掉对 NSData 的 hook,会跟高德的 SDK 用到的某个函数有点冲突,我这边测试用例过不了就直接去掉了。

所有被 hook 的函数都是直接从系统 API 选取的,基本上能拦截掉绝大部分的常见越界类和空值类数据引起的崩溃。

KVO,NSTimer 强引用这类能用代码规范解决的,本库不做额外的防护。

避免越界的类

NSString
NSArray
NSDictionary
NSSet
NSCache
NSUserDefaults
NSAttributedString

此外,用户自定义避免 unrecognized selector sent to instance 崩溃。

开始

$ pod 'FFExtension'

你只需要导入一个头文件,如 import <FFManager.h>

然后将以下代码放入你的项目中,可能在 application:didFinishLaunchingWithOptions: 方法中,确保类在整个应用生命周期中不被销毁。

__weak typeof(self) weakSelf = self;
[[FFManager sharedInstance] startWorkWithOption:FFHookOptionAll unrecogziedSelectorClassPrefixs:@[@"SSZ"] callBackBlock:^(NSDictionary *exceptionDic) {
        [weakSelf reportExecptionToBugly:exceptionDic];
}];

如上所述,传入 @"SSZ" 则可以保护所有以 SSZ 开头的类,避免 unrecognized selector sent to instance 这种崩溃。

就像这样

#pragma mark - Report Exception To Bugly
- (void)reportExecptionToBugly:(NSDictionary *)exceptionDic
{
    if (exceptionDic) {
        NSString *name = [exceptionDic objectForKey:FF_Name];
        NSString *reason = [exceptionDic objectForKey:FF_Reason];
        NSDictionary *extraDic = [exceptionDic objectForKey:FF_ExtraDic];
        NSArray *callStack = [exceptionDic objectForKey:FF_CallStackSymbols];
        
        [Bugly reportExceptionWithCategory:3 name:name reason:reason callStack:callStack 			extraInfo:extraDic terminateApp:NO];
    }
}

提示: classPrefixs 是你想避免 unrecognized selector sent to instance 崩溃的自己的类。

- (void)startWorkWithOption:(FFHookOption)option unrecogziedSelectorClassPrefixs:(NSArray<NSString *> *)classPrefixs callBackBlock:(FFExceptionBlock)block;

安全的方法示例

NSArray

- (BOOL)writeToURL:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)error;
- (id)objectAtIndexedSubscript:(NSUInteger)index;
- (id)objectAtIndexedSubscriptArrayM:(NSUInteger)index;
- (id)objectAtIndex:(NSUInteger)index;
- (instancetype)initWithObjects:(const id _Nonnull [_Nullable])objects count:(NSUInteger)cnt;
- (NSArray *)arrayByAddingObject:(id)anObject;
- (void)getObjects:(id _Nonnull __unsafe_unretained [_Nonnull])objects range:(NSRange)range;
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range;
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range;
- (NSArray *)subarrayWithRange:(NSRange)range;
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeObjectsInRange:(NSRange)range;
- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes;
- (void)removeObject:(id)anObject inRange:(NSRange)range;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)removeObjectAtIndexArrayM:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2;
- (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray;
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray range:(NSRange)otherRange;
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects;

等等...


通过使用 方法交换 来完成此操作,无需 try-catch

祝你愉快!