美文网首页
iOS 在debug和release下的ARC

iOS 在debug和release下的ARC

作者: fulen | 来源:发表于2018-10-19 15:17 被阅读34次

最近公司项目遇到一个问题,线上的app不能收到聊天记录,以往的版本中都是OK的,但是最近的一个版本没法收到通知,究其原因是因为在release环境下的内存管理问题,下面直接上代码

- (void)invokeEvent:(NSString *)eventName withArgs:(NSArray *)args {
    SRSubscription *eventObj = _subscriptions[eventName];
    if(eventObj != nil && eventObj.object != nil) {
        NSMethodSignature *signature = [eventObj.object methodSignatureForSelector:eventObj.selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        NSUInteger numberOfArguments = [signature numberOfArguments] - 2;
        
        if (args.count != numberOfArguments) {
            SRLogConnectionInfo(@"Callback for event '%@' is configured with %ld arguments, received %ld parameters instead.",eventName, (unsigned long)numberOfArguments, (unsigned long)args.count);
        }
        
        [invocation setSelector:eventObj.selector];
        [invocation setTarget:eventObj.object];
        for(int i =0; i< MIN([args count], numberOfArguments); i++) {
            int arguementIndex = 2 + i;
            __weak NSString *argument = args[i];
            [invocation setArgument:&argument atIndex:arguementIndex];
        }
        [invocation invoke];
    }
}

以上是第三方库signalR的部分代码,我们在__weak NSString *argument = args[i];做了部分修改,我们想传递一个数组出去,于是修改成如下代码

- (void)invokeEvent:(NSString *)eventName withArgs:(NSArray *)args {
    SRSubscription *eventObj = _subscriptions[eventName];
    if(eventObj != nil && eventObj.object != nil) {
        
        NSMethodSignature *signature = [eventObj.object methodSignatureForSelector:eventObj.selector];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        NSUInteger numberOfArguments = [signature numberOfArguments] - 2;
        
        if (args.count != numberOfArguments) {
            SRLogConnection(@"Callback for event '%@' is configured with %ld arguments, received %ld parameters instead.",eventName, (unsigned long)numberOfArguments, (unsigned long)args.count);
        }
        
        [invocation setSelector:eventObj.selector];
        [invocation setTarget:eventObj.object];
        for(int i =0; i< MIN([args count], numberOfArguments); i++) {
            int arguementIndex = 2 + i;
            __weak id argument = [OSPJSONUtil objectFromJSONValue:args[i] class:eventObj.argClasses[i]];
            [invocation setArgument:&obj atIndex:arguementIndex];
        }
        [invocation invoke];
    }
}

问题来了,第三方库signalR内部做了内存管理,将我们上面创建的对象加入到autoreleasepool中了,在debug环境下是没有问题的,但是上线release就会导致argument--weak之后立马释放,而导致取不到值

2、我们新建一个项目测试一下

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSArray *arr = @[@"testArray",@"testArray",@"testArray"];
    __weak NSArray *testArray = arr;
    NSLog(@"testArray=%@, &testArray=%p, &arr=%p",testArray,testArray,arr);
    
    __weak NSArray *testArray1 = @[@"testArray1",@"testArray1",@"testArray1"];
    NSLog(@"testArray1=%@",testArray1);
    
    @autoreleasepool {
        __weak NSArray *testArray2 = @[@"testArray2",@"testArray2",@"testArray2"];
        NSLog(@"testArray2=%@",testArray2);
        
        NSArray *arr = @[@"testArray3",@"testArray3",@"testArray3"];
        __weak NSArray *testArray3 = arr;
        NSLog(@"testArray3=%@ ,&testArray=%p, &arr=%p",testArray3,testArray3,arr);
        
        __weak NSString *testString = @"testString";
        NSLog(@"testString=%@",testString);
        
    }
}
// 以上是release模式下的代码,下面附带截图
release模式

可以看到在testArray1 和testArray2处有两个警告,意思是对象在创建完成后会被立马释放掉,我们看下打印结果


release模式打印结果

接下来我们切换到debug模式,以下为debug模式打印结果


debug模式打印结果

结论:
release模式下,__weak 创建的对象会被立刻释放掉,但是NSString对象不会被立刻释放掉,
debug模式下,__weak 创建的对象不会被立刻释放掉

相关文章

网友评论

      本文标题:iOS 在debug和release下的ARC

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