美文网首页
iOS NSArray NSDictionary 防止崩溃方案

iOS NSArray NSDictionary 防止崩溃方案

作者: _Waiting_ | 来源:发表于2022-08-16 11:02 被阅读0次

数组

//
//  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:@"数组存在空值"];
                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:@"数组存在空值"];
                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:)];
}

///数组越界
-(id)hook_arrFun1ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun1ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"数组越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun1ObjectAtIndex:index];
    }
}
///数组越界
-(id)hook_arrFun2ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun2ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"数组越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun2ObjectAtIndex:index];
    }
}
///数组越界
-(id)hook_arrFun3ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun3ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"数组越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun3ObjectAtIndex:index];
    }
}
///数组越界
-(id)hook_arrFun4ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun4ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"数组越界"];
            return nil;
        } @finally {
            
        }
    }
    else{
        return [self hook_arrFun4ObjectAtIndex:index];
    }
}
///数组越界
-(id)hook_arrFun5ObjectAtIndex:(NSUInteger)index{
    if (index > self.count - 1 || !self.count){
        @try {
            return [self hook_arrFun5ObjectAtIndex:index];
        } @catch (NSException *exception) {
            [self printError:@"数组越界"];
            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:@"数组越界"];
            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:@"添加数据异常"];
    }else if ((self.count + 1 < index)) {
        [self printError:@"添加数据位置异常"];
    }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


注:因为该方法是利用runtime进行方法交换,所以会导致部分性能降低,所以对于有性能要求的请慎用此方法。另外一种方案就是自己写一个扩展 NSArray 和 NSDictionary 的方法,然后全局声明,整个工程都要以此为基础进行赋值和取值。

相关文章

网友评论

      本文标题:iOS NSArray NSDictionary 防止崩溃方案

      本文链接:https://www.haomeiwen.com/subject/dpmrgrtx.html