美文网首页
iOS-NSMutableArray+runtime交换方法

iOS-NSMutableArray+runtime交换方法

作者: 路飞_Luck | 来源:发表于2018-04-16 23:00 被阅读178次

    导读

    当对一个可变数组操作很频繁,并且在多个线程操作同一个可变数组时,发生数组越界等奔溃是很常见的.所以使用runtime,对其方法进行交换.然后在交换方法中对增,删,改,查等做保护机制就可以避免类似情况发生.

    源代码
    1.新建一个NSMutableArray的分类

    NSMutableArray+ SafeAccess.h文件声明

    #import <Foundation/Foundation.h>
    
    @interface NSMutableArray (SafeAccess)
    
    @end
    
    2.文件实现
    // 需要导入runtime.h文件
    #import <objc/runtime.h>
    

    然后在load方法中声明进行方法交换声明

    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            id obj = [[self alloc] init];
            [obj swizzleMethod:@selector(addObject:) withMethod:@selector(safeAddObject:)];
            [obj swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(safeObjectAtIndex:)];
            [obj swizzleMethod:@selector(removeObjectAtIndex:) withMethod:@selector(safeRemoveObjectAtIndex:)];
        });
    }
    
    - (void)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector {
        Class cls = [self class];
    
        Method originalMethod = class_getInstanceMethod(cls, origSelector);
        Method swizzledMethod = class_getInstanceMethod(cls, newSelector);
    
        BOOL didAddMethod = class_addMethod(cls,
                                            origSelector,
                                            method_getImplementation(swizzledMethod),
                                            method_getTypeEncoding(swizzledMethod));
        if (didAddMethod) {
            class_replaceMethod(cls,
                                newSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    

    为什么在load方法中进行声明?

    可以参考iOS开发+(void)load与+(void)initialize区别,里面做了很详细的介绍.

    三个交换方法的实现

    - (void)safeAddObject:(id)anObject {
        if (anObject) {
            [self safeAddObject:anObject];
        }else{
            NSLog(@"obj is nil");
        }
    }
    
    - (id)safeObjectAtIndex:(NSInteger)index {
        if(index<[self count]){
            return [self safeObjectAtIndex:index];
        }else{
            NSLog(@"index is beyond bounds ");
        }
        return nil;
    }
    
    - (void)safeRemoveObjectAtIndex:(NSUInteger)index {
        if (index >= [self count]) {
            return;
        }
        
        return [self safeRemoveObjectAtIndex:index];
    }
    
    3.调用
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        [self syncMutableArray];
    }
    
    - (void)syncMutableArray {
        NSMutableArray *safeArr = [[NSMutableArray alloc] init];
        
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        for ( int i = 0; i < 1000; i ++) {
            dispatch_async(queue, ^{
                NSLog(@"添加第%d个",i);
                [safeArr addObject:[NSString stringWithFormat:@"%d",i]];
            });
            
            dispatch_async(queue, ^{
                NSLog(@"删除第%d个",i);
                [safeArr removeObjectAtIndex:i];
            });
            
            dispatch_async(queue, ^{
                NSLog(@"读取第%d个数据:%@",i,[safeArr objectAtIndex:i]);
            });
        }
    }
    

    项目连接地址

    总结

    结果运行良好,没有发生奔溃,因为即使多个线程同时操作一个可变数组,因为已经对其方法做了交换,在交换方法中已经做了包含措施,所以不会发生crash.

    相关文章

      网友评论

          本文标题:iOS-NSMutableArray+runtime交换方法

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