ARC下内存泄漏

对于 ARC 下所造成的内存泄漏进行整理和归纳,查找了一下其他人的博客和自己的一些理解,如果有需要可以参考一下!如果有存在错误可以发我的邮箱([email protected])告知谢谢

遍历数组

1. 第一种遍历数组产生的 bug

      
      
1
2
3
4
5
6
7
8
9
10
      
      
NSMutableArray * arr = [NSMutableArray arrayWithArray:@[@"a",@"b",@"c",@"d",@"e",@"f",@"g",@"h"]];
for (NSString * str in arr) {
if ([str isEqualToString:@"f"]) {
[arr removeObject:str];
}
}

产生错误
ss

原因:对象类型是弱引用,数组中的元素被释放导致也无法找到相应的对象
在移除后边加上 break, 直接跳出不会崩溃

2. 不会产生 bug

      
      
1
2
3
4
5
6
      
      
for (int i = 0; i < arr.count; i ++) {
NSString * str = arr[i];
if ([str isEqualToString:@"f"]) {
[arr removeObject:str];
}
}

原因:NSString * str = arr[i]因为 NSString 对对象默认是 Strong 强引用,所以对移除的 str 持有了一份就不会因为 arr 中的对象被释放而产生 bug

3. 第三种遍历

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      
      
NSMutableArray * arr;
{
Person * p1 = [[Person alloc] init];
Person * p2 = [[Person alloc] init];
Person * p3 = [[Person alloc] init];
Person * p4 = [[Person alloc] init];
Person * p5 = [[Person alloc] init];
Person * p6 = [[Person alloc] init];
arr = [NSMutableArray arrayWithArray:@[p1,p2,p3,p4,p5,p6]];
}
//由于 arr 对于 person 持有所以 person 不会被释放!
[arr enumerateObjectsUsingBlock:^(Person* p,NSUInteger idx,BOOL* _Nonnullstop) {
if (idx == 2) {
[arr removeObjectAtIndex:idx];
}
}];
//将 p3 移除后,在这个作用域之后被释放,其他的 person 会在 arr 出了作用域后被释放。

原因:当Person出第一个作用域时不会被释放,因为arr 对其持有一份 retainCount+1,在遍历时将其中一个元素移除出了作用域(遍历的)就会立刻被释放,其他的当arr 完成遍历之后出了 arr 所在作用域会被释放。

@try@catch@finally

      
      
1
2
3
4
5
6
7
8
9
10
11
12
      
      
@try {
Toys * toy = [[Toys alloc] init];
Person * p7 = [arr objectAtIndex:7];
//无法被执行
p7.beer = toy;
}
@catch (NSException *exception) {
NSLog(@"捕捉到的异常是:%@", exception);
}
@finally {
}

原因:因为取数组中第7个Person数组越界,之后的代码不会被执行导致Toys对象创建后无法被释放,导致内存泄漏。

performSelector

      
      
1
2
3
      
      
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self performSelector:@selector(test:) withObject:arr afterDelay:3];
});

原因: test 方法无法被调用,因为子线程中没有定时器。
performSelector 关于内存管理的执行原理是这样的执行 [self performSelector:@selector(test:) withObject:object afterDelay:3]; 的 时候,系统会将object的引用计数加1,执行完这个方法时,还会将object的引用计数减1,由于延迟这时object的 引用计数没有减少到0,也就导致了切换场景dealloc方法没有被调用,出现了内存泄露。
所以最后我的解决办法就是取消那些还没有来得及执行的延时函数,代码很简单:

      
      
1
      
      
[NSObject cancelPreviousPerformRequestsWithTarget:self]

当然你也可以一个一个得这样用:

      
      
1
      
      
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(test:) object:nil]

加上了这个以后,切换场景也就很顺利地执行了dealloc方法,至此问题解决!

NSTimer

在使用 NSTimer addtarget 时,为了防止 target 被释放而导致的程序异常,timer 会持有 target,所以这也是一处内存泄露的隐患。

      
      
1
      
      
_timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];

因为是 target 对 self 强引用导致 timer 的 retainCount >= 1,无法调用 dealloc 方法,导致 NSTimer 无法释放。

addObserver

NSNotificationcenter 需要 removeObserver 的原因是如果不移除的话,被观察者那么还会继续发送消息。如果此时观察者已经释放,消息会转发给其他对象,有可能造成严重的问题[理解消息发送机制]

原文:大专栏  ARC下内存泄漏


猜你喜欢

转载自www.cnblogs.com/wangziqiang123/p/11641529.html
今日推荐