iOS NSArray NSDictionary 防止崩潰方案

數(shù)組

//
//  NSArray+beyond.h
//  HanTest-beyond
//
//  Created by han on 2022/7/25.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSArray (beyond)

@end

NS_ASSUME_NONNULL_END

//
//  NSArray+beyond.m
//  HanTest-beyond
//
//  Created by han on 2022/8/15.
//

#import "NSArray+beyond.h"
#import <objc/runtime.h>

@implementation NSArray (beyond)
+(void)load{
    [super load];
    [self swizzleMethod];
    [self swizzleMutableMethod];
}

+(void)swizzleMethodWithClassName:(const char * _Nonnull)className  NewSEL:(SEL)newSEL oldSEL:(SEL)oldSEL{
    Method oldObjectAtIndex = class_getInstanceMethod(objc_getClass(className), oldSEL);
    Method newObjectAtIndex = class_getInstanceMethod(objc_getClass(className), newSEL);
    method_exchangeImplementations(oldObjectAtIndex, newObjectAtIndex);
}

#pragma mark - NSArray

+(void)swizzleMethod{
    [self swizzleInit];
    [self swizzleObjectAtIndex];
}

+(void)swizzleInit{
    [self swizzlePlaceholderMethodWithNewSEL:@selector(hook_initWithObjects:count:) oldSEL:@selector(initWithObjects:count:)];
}

+(void)swizzlePlaceholderMethodWithNewSEL:(SEL)newSEL oldSEL:(SEL)oldSEL{
    [self swizzleMethodWithClassName:"__NSPlaceholderArray" NewSEL:newSEL oldSEL:oldSEL];
}
- (instancetype)hook_initWithObjects:(id  _Nonnull const [])objects count:(NSUInteger)cnt{
    
    if (cnt > 0) {
        for (NSUInteger i=0; i<cnt; i++) {
            if(objects[i]==nil){
                [self printError:@"數(shù)組存在空值"];
                return @[];
            }
        }
    }
    return [self hook_initWithObjects:objects count:cnt];
}
+ (instancetype)hook_initWithObjects:(id  _Nonnull const [])objects count:(NSUInteger)cnt{
    
    if (cnt > 0) {
        for (NSUInteger i=0; i<cnt; i++) {
            if(objects[i]==nil){
                [self printError:@"數(shù)組存在空值"];
                return @[];
            }
        }
    }
    return [self hook_initWithObjects:objects count:cnt];
}
+(void)swizzleObjectAtIndex{
    
    [self swizzleMethodWithClassName:"__NSArrayI" NewSEL:@selector(hook_arrFun1ObjectAtIndex:) oldSEL:@selector(objectAtIndex:)];
    [self swizzleMethodWithClassName:"__NSArray0" NewSEL:@selector(hook_arrFun2ObjectAtIndex:) oldSEL:@selector(objectAtIndex:)];
    [self swizzleMethodWithClassName:"__NSSingleObjectArrayI" NewSEL:@selector(hook_arrFun3ObjectAtIndex:) oldSEL:@selector(objectAtIndex:)];
    [self swizzleMethodWithClassName:"__NSArrayI" NewSEL:@selector(hook_arrFun4ObjectAtIndex:) oldSEL:@selector(objectAtIndexedSubscript:)];
    [self swizzleMethodWithClassName:"NSConstantArray" NewSEL:@selector(hook_arrFun5ObjectAtIndex:) oldSEL:@selector(objectAtIndex:)];
}

///數(shù)組越界
-(id)hook_arrFun1ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun1ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun1ObjectAtIndex:index];
    }
}
///數(shù)組越界
-(id)hook_arrFun2ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun2ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun2ObjectAtIndex:index];
    }
}
///數(shù)組越界
-(id)hook_arrFun3ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun3ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun3ObjectAtIndex:index];
    }
}
///數(shù)組越界
-(id)hook_arrFun4ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun4ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun4ObjectAtIndex:index];
    }
}
///數(shù)組越界
-(id)hook_arrFun5ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun5ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun5ObjectAtIndex:index];
    }
}
#pragma mark - NSMutableArray
+(void)swizzleMutableMethod{
    [self swizzleMutableObjectAtIndex];
    [self swizzleMutableInsertObject];
}
+(void)swizzleMutableObjectAtIndex{
    [self swizzleMethodWithClassName:"__NSArrayM" NewSEL:@selector(hook_objectAtIndex:) oldSEL:@selector(objectAtIndex:)];
}
-(id)hook_objectAtIndex:(NSUInteger)index{
    
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_objectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"數(shù)組越界"];
            return nil;
        } @finally {

        }
    }
    else{
        return [self hook_objectAtIndex:index];
    }
    return nil;
}
+(void)swizzleMutableInsertObject{
    [self swizzleMethodWithClassName:"__NSArrayM" NewSEL:@selector(hook_insertObject:atIndex:) oldSEL:@selector(insertObject:atIndex:)];
}

- (void)hook_insertObject:(id)anObject atIndex:(NSUInteger)index{
    if ([self isBlank:anObject]) {
        [self printError:@"添加數(shù)據(jù)異常"];
    }else if ((self.count + 1 < index)) {
        [self printError:@"添加數(shù)據(jù)位置異常"];
    }else{
        [self hook_insertObject:anObject atIndex:index];
    }
    
}
#pragma mark - private
- (BOOL)isBlank:(id)obj {
    if (obj == nil)return YES;
    if ([obj isKindOfClass:[NSNull class]]) return YES;
    return NO;
}
+ (BOOL)isBlank:(id)obj {
    if (obj == nil)return YES;
    if ([obj isKindOfClass:[NSNull class]]) return YES;
    return NO;
}
-(void)printError:(NSString *)explain{
    NSLog(@"??????????");
    NSLog(@"%@",explain);
    NSLog(@"??????????");
}
+(void)printError:(NSString *)explain{
    NSLog(@"??????????");
    NSLog(@"%@",explain);
    NSLog(@"??????????");
}
@end

字典

//
//  NSDictionary+beyond.h
//  HanTest-beyond
//
//  Created by han on 2022/8/15.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSDictionary (beyond)

@end

NS_ASSUME_NONNULL_END

//
//  NSDictionary+beyond.m
//  HanTest-beyond
//
//  Created by han on 2022/8/15.
//

#import "NSDictionary+beyond.h"
#import <objc/runtime.h>
@implementation NSDictionary (beyond)

+(void)load{
    [super load];
    [self swizzleMethod];
    [self swizzleMutableMethod];
}

+(void)swizzleMethodWithClassName:(const char * _Nonnull)className  NewSEL:(SEL)newSEL oldSEL:(SEL)oldSEL{
    Method oldObjectAtIndex = class_getInstanceMethod(objc_getClass(className), oldSEL);
    Method newObjectAtIndex = class_getInstanceMethod(objc_getClass(className), newSEL);
    method_exchangeImplementations(oldObjectAtIndex, newObjectAtIndex);
}
#pragma mark - NSDictionary

+(void)swizzleMethod{
    [self swizzleInit];
}
+(void)swizzleInit{
    [self swizzlePlaceholderMethodWithNewSEL:@selector(hook_initWithObjects:forKeys:count:) oldSEL:@selector(initWithObjects:forKeys:count:)];
}

+(void)swizzlePlaceholderMethodWithNewSEL:(SEL)newSEL oldSEL:(SEL)oldSEL{
    [self swizzleMethodWithClassName:"__NSPlaceholderDictionary" NewSEL:newSEL oldSEL:oldSEL];
}
- (instancetype)hook_initWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt {
    id safeObjects[cnt];
    id safeKeys[cnt];
    NSUInteger j = 0;
    for (NSUInteger i = 0; i < cnt; i++) {
        id key = keys[i];
        id obj = objects[i];
        if ([self isBlank:key]) {
            [self printError:@"字典存在Key為空"];
            return nil;
        }
        if ([self isBlank:obj]) {
            [self printError:@"字典存在Value為空"];
            return nil;
        }
        safeKeys[j] = key;
        safeObjects[j] = obj;
        j++;
    }
    return [self hook_initWithObjects:safeObjects forKeys:safeKeys count:j];
}
+ (instancetype)hook_initWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt {
    id safeObjects[cnt];
    id safeKeys[cnt];
    NSUInteger j = 0;
    for (NSUInteger i = 0; i < cnt; i++) {
        id key = keys[i];
        id obj = objects[i];
        if ([self isBlank:key]) {
            [self printError:@"字典存在Key為空"];
            return nil;
        }
        if ([self isBlank:obj]) {
            [self printError:@"字典存在Value為空"];
            return nil;
        }
        safeKeys[j] = key;
        safeObjects[j] = obj;
        j++;
    }
    return [self hook_initWithObjects:safeObjects forKeys:safeKeys count:j];
}


#pragma mark - NSMutableDictionary

+(void)swizzleMutableMethod{
    [self swizzleRemoveObject];
}

+(void)swizzleRemoveObject{
    [self swizzleMethodWithClassName:"__NSDictionaryM" NewSEL:@selector(hook_removeObjectsForKeys:) oldSEL:@selector(removeObjectsForKeys:)];
    [self swizzleMethodWithClassName:"__NSDictionaryM" NewSEL:@selector(hook_removeObjectForKey:) oldSEL:@selector(removeObjectForKey:)];
}
- (void)hook_removeObjectsForKeys:(NSArray *)keyArray{
    for (id obj in keyArray) {
        if ([self isBlank:obj]) {
            [self printError:@"字典 刪除存在Key為空"];
            return;
        }
    }
}
- (void)hook_removeObjectForKey:(id)aKey{
    if ([self isBlank:aKey]) {
        [self printError:@"字典 刪除存在Key為空"];
        return;
    }
    [self hook_removeObjectForKey:aKey];
}

#pragma mark - private
- (BOOL)isBlank:(id)obj {
    if (obj == nil)return YES;
    if ([obj isKindOfClass:[NSNull class]]) return YES;
    return NO;
}
+ (BOOL)isBlank:(id)obj {
    if (obj == nil)return YES;
    if ([obj isKindOfClass:[NSNull class]]) return YES;
    return NO;
}
-(void)printError:(NSString *)explain{
    NSLog(@"??????????");
    NSLog(@"%@",explain);
    NSLog(@"??????????");
}
+(void)printError:(NSString *)explain{
    NSLog(@"??????????");
    NSLog(@"%@",explain);
    NSLog(@"??????????");
}
@end


注:因?yàn)樵摲椒ㄊ抢胷untime進(jìn)行方法交換,所以會導(dǎo)致部分性能降低,所以對于有性能要求的請慎用此方法。另外一種方案就是自己寫一個擴(kuò)展 NSArray 和 NSDictionary 的方法,然后全局聲明,整個工程都要以此為基礎(chǔ)進(jìn)行賦值和取值。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容