iOS使用runtime监测UIViewController的dealloc

JerryXia 发表于 , 阅读 (0)

iOS使用runtime监测UIViewController的dealloc

平时在iOS开发的时候,很多情况会导致内存泄露。有时候因为循环引用,导致了UIViewController不回收,还有其它好多原因。一般检测内存泄露都是使用XcodeInstruments工具。但是这个工具有点复杂,新手入门还是有点难度。所以想到了使用runtime替换UIViewController-(void)dealloc:方法的实现,检测ViewController是否被释放,从而知道ViewController里面有没有内存泄露。

runtime的相关细节就不说了,不理解也能用,复制放到项目里面就好了。

一、思路

  1. 需要被替换的方法是UIViewController-(void)dealloc:,所以新建一个UIViewControllerCategory,在其+(void)load里面执行方法替换。
  2. 替换的新方法里面做一个简单地log一下当前UIViewController的类名就好了就好了,即当UIViewController被回收的时候,log其类名。

二、实现

1.新建一个UIViewController的Category,编写新的dealloc方法。代码如下(可自行修改):

1
2
3
4
5
6
7
8
- (void)skyLogInDealloc {
printf("\n");
NSLog(@"-------------start-------------");
NSLog(@"Dealloc : %@", NSStringFromClass([self class]));
NSLog(@"--------------end--------------");
printf("\n");
[self skyLogInDealloc];
}

2.重写+(void)onLoad:方法。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
+ (void)load {
[super load];
SEL originSEL = NSSelectorFromString(@"dealloc");
SEL swapSEL = @selector(skyLogInDealloc);
Method originMethod = class_getInstanceMethod(self, originSEL);
Method swapMethod = class_getInstanceMethod(self, swapSEL);
IMP originIMP = method_getImplementation(originMethod);
IMP swapIMP = method_getImplementation(swapMethod);
BOOL didAddMethod = class_addMethod(self, originSEL, swapIMP, method_getTypeEncoding(originMethod));
if(didAddMethod) {
class_replaceMethod(self, swapSEL, originIMP, method_getTypeEncoding(originMethod));
} else {
method_exchangeImplementations(originMethod, swapMethod);
}
}

完整的m文件实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#if DEBUG
+ (void)load {
[super load];
SEL originSEL = NSSelectorFromString(@"dealloc");
SEL swapSEL = @selector(skyLogInDealloc);
Method originMethod = class_getInstanceMethod(self, originSEL);
Method swapMethod = class_getInstanceMethod(self, swapSEL);
IMP originIMP = method_getImplementation(originMethod);
IMP swapIMP = method_getImplementation(swapMethod);
BOOL didAddMethod = class_addMethod(self, originSEL, swapIMP, method_getTypeEncoding(originMethod));
if(didAddMethod) {
class_replaceMethod(self, swapSEL, originIMP, method_getTypeEncoding(originMethod));
} else {
method_exchangeImplementations(originMethod, swapMethod);
}
}
- (void)skyLogInDealloc {
printf("\n");
NSLog(@"-------------start-------------");
NSLog(@"Dealloc : %@", NSStringFromClass([self class]));
NSLog(@"--------------end--------------");
printf("\n");
[self skyLogInDealloc];
}
#endif

三、部分细节

  1. 在ARC下,使用@selector(dealloc:)会报错,所以只好这样子获取它的SEL: NSSelectorFromString(@"dealloc")
  2. DEBUG是一个宏,当构建项目使用Debug的时候,其值会为YES,当使用Release的时候,其值会是NO。加上去就是为了发布的时候,也不需要担心忘记将其移除功能。

附上github地址: https://github.com/skytoup/SkyLogInDealloc

本文为博主skytoup原创文章,未经博主skytoup允许不得转载。