数组
//
// 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 的方法,然后全局声明,整个工程都要以此为基础进行赋值和取值。