最近公司项目遇到一个问题,线上的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 创建的对象不会被立刻释放掉
网友评论