前语
咱们平常开发中,如果运用的是ARC形式,那么一旦运用performSelector
去调用函数,就一定会呈现下面的内存正告现象。
你或许会疑惑,只不过是用了 “performSelector:” 去调用办法,为什么会提示或许会引起内存走漏问题呢?然后开发节奏严重的情况下,大部分人去办法上网搜一下处理办法都在看到如何处理这个正告,然后把代码仿制黏贴一下,发现可行后就把问题放下了,那么呈现这个正告的原因到底是因为什么?这篇文章现在就来解答一下这个问题。点个保藏,日后有空看看原理时再来看也不迟~
一、告警的原因解答
在ARC下运用performSelector:
函数会呈现这个正告的主要原因是因为:编译器无法确认在运转时执行的办法是否需求内存办理。 在编译时,编译器并不知道performSelector:
将要执行哪个办法,所以无法在编译时为该办法生成正确的内存办理代码,然后或许会有内存走漏的危险。
咱们都知道,在ARC环境下,编译器会主动帮咱们办理内存,当目标的引证计数为0时,编译器会主动开释这个目标,无需手动调用release
办法。然而,performSelector:
函数是在运转时依据传入的参数来动态调用办法的。在编译时,编译器并不知道将要调用的办法是什么,也不了解其办法签名及返回值,甚至连是否有返回值都不清楚。并且,因为编译器不知道办法名,所以就没办法运用 ARC 的内存办理规矩来断定返回值是不是应该开释。因而,ARC 采用了比较慎重的做法,便是不增加开释操作。然而这么做或许导致内存走漏,因为办法在返回目标时或许现已将其保留了。
举个比如,假如咱们定义了一个Person
类,然后创立办法和开释办法中参加相关日志:
@interface Person : NSObject
@end
@implementation Person
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"我创立了");
}
return self;
}
-(void)dealloc
{
NSLog(@"我开释了");
}
@end
现在咱们先用objc代码正常new一个Person
类
[Person new];
运转成果如下
然后咱们把生成的函数改成运用performSelector:
函数来调用new
办法:
[Person performSelector:@selector(new)];
运转成果如下
从在上面的代码中,能够得出运用performSelector:
函数生成的实例并没有打印开释日志,虽然new
函数也生成了一个Person
类实例,可是在编译器在编译时期并不知道是什么函数,有没有返回值,所以统一让ARC采用不开释的保守操作,因而ARC并没有去开释这个实例,然后导致了内存走漏。
二、告警的处理办法
其实在网上搜一下,就能找到许多处理的版本,第一个便是用编译指令去掉正告,其函数如下
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//performSelector函数
#pragma clang diagnostic pop
这段代码的作用是忽略运用performSelector:
函数或许导致内存走漏的正告。可是如果要运用这个处理办法,咱们需求确保自己的代码中不存在内存走漏的危险,这是有危险的,因而并不主张运用。
第二个办法便是去获取performSelector:
函数想调用的那个办法对应的对应的 C 函数指针。此处对应比如里的是Person
类目标的new
办法的函数指针,然后运用该函数指针来调用new
办法创立了一个Person
类的实例。可是需求留意的是,这种办法也仅仅消除了正告,实践如果仍是调用new
,体系并不会帮咱们开释该实例,需求咱们运用CFBridgingRelease
函数将实例转换成Core Foundation目标,并手动开释其内存。写法如下
Class personClass = [Person class];
SEL selector = @selector(new);
IMP imp = [personClass methodForSelector:selector];
Person *(*func)(id, SEL) = (void *)imp;
Person *person = func(personClass, selector);
// 运用person目标
// ...
// 开释person目标
CFBridgingRelease((__bridge CFTypeRef)(person));
运转成果如下
三、总结
本文依据我的理解和实践总结出了ARC中performSelector:
的内存走漏问题的原因和处理办法,因为Objc是一门非常动态的语言,开发者能够随意调用任何办法,performSelector:
便是其中之一,可是这个正告呈现的原因仍是需求留意的,虽然有些代码仍是会经常用到它们,可是如果不想呈现问题主张仍是尽量少用。