2019-06-26 iOS野指针

原文地址: https://ctinusdev.github.io/2017/03/03/WriteWildPointer/

野指针的bug应该算是最难查的bug之一了,因为其随机性强,且难以定位,下面就终结了几类常见的高概率野指针写法。

1、对象释放后,指针没有置空。

常见写法1:

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 396px;">

@property (nonatomic, unsafe_unretained) id obj;

</pre>

|

问题原因:
unsafe_unretained申明的obj并不会在对象释放时将指针置空,如果对象释放之后,继续使用obj就有可能出现野指针的问题。
解决方案:
尽量使用weak|strong|copy等来代替unsafe_unretained来修饰属性。如果一定要使用unsafe_unretained,记得对象释放后,将指针置空。

常见写法2:

objc_setAssociatedObject方法中该用OBJC_ASSOCIATION_RETAIN_NONATOMIC修饰的对象误用成OBJC_ASSOCIATION_ASSIGN
问题原因:
这个问题和上面的常见写法1问题是类似的,就不重复了。

常见写法3:

NSNotification/KVO 只addObserver并没有removeObserver

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 1054px;">

@interface viewController: UIViewController

@property (nonatomic, strong) id obj;

@end

@implementation viewController

-(void)someButtonClick:(id)sender

{

[self.obj addObserver:self forKeyPath:@"someKey" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

}

-(void)dealloc

{

//没有移除观察者

}

@end

</pre>

|

问题原因:
self.obj添加了self作为观察者后,是通过unsafe_unretained指针引用的self,如果对象释放之前不移除观察,self.obj对应keyPath发生变化时,仍然会去尝试给self指向的对象发送通知。就可能会出现野指针了。
解决方案:
1、原始方法,记得addObserver和removeObserver成对出现。
2、利用KVOController

2、对象提前释放了

常见写法1:

异步方法block回调中,没有强引用self。

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 302px;">

__weak typeof(self) weakself = self;

[obj method:^(id result) {

[weakself someMethod];

}];

-(void)someMethod

{

self.test = ....;

...

}

</pre>

|

问题原因:
ARC下,由于性能原因self既不是strong也不是weak,而是unsafe_unretained的。上面代码block并没有引用强引用self。若是在执行[weakSelf someMethod]时,刚好self被释放了,那么self.test 这句的执行就有可能造成野指针崩溃。
解决方案:
在进入block时,先强引用weakself。

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 427px;">

__weak typeof(self) weakself = self;

[obj method:^(id result) {

    __strong typeof(self) strongself = weakSelf;

    [strongself someMethod];

}];

</pre>

|

常见写法2:

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 498px;">

@interface viewController: UIViewController

@end

@implementation viewController

-(void)someButtonClick:(id)sender

{

[self.navigationController popViewControllerAnimated:NO];

[self someMethod];

}

@end

</pre>

|

问题原因:
由于self在pop之后就会被释放,在pop之后,继续使用self,就可能会导致野指针。
解决方案:
在pop和dismiss之后不要在使用self,关于self的操作都在pop和dismiss之前。

3、对象的多次释放。

常见写法1:

多个线程同时对某个对象赋值

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

5

6

7

8

9

10

11

12

13

14

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 678px;">

@interface SomeClass: NSObject

@property (nonatomic, strong) NSArray *array;

@end

@implementation SomeClass

  • (void)viewDidLoad

{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    self.array = @[@"test"];

});

self.array = @[@"test"];

}

@end

</pre>

|

问题原因:
在调用setArray:时,新的值会被retain,旧的值会被release。如果两个线程同时执行了setArray:,那么旧的值就可能会release放两次。

解决方案:
找个问题不难解决,对象赋之前先加锁,再赋值就可以解决这类问题。

常见写法2:

CoreFoundation层对象Toll-Free Bridging到Foundation层中,已经用了__bridge_transfer关键字转移了对象的所有权之后,又对CoreFoundation层对象调用了一次CFRelease

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(134, 145, 148); background: rgb(239, 242, 243); line-height: 1.6; border: none; text-align: right;">

1

2

3

4

</pre>

|

<pre style="overflow: auto; font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; font-size: 13px; margin: 0px; padding: 10px; color: rgb(77, 77, 76); background: rgb(247, 247, 247); line-height: 1.6; border: none; width: 474px;">

CFUUIDRef uuid = CFUUIDCreate(NULL);

CFStringRef cfString = CFUUIDCreateString(NULL, uuid);

NSString *string = (__bridge_transfer NSString *)cfString;

CFRelease(cfString);

</pre>

|

问题原因:
使用__bridge_transfer之后,cfString的所有权已经交由ARC处理,这时再次接手动调用release,会导致重复释放的问题。

解决方案:
1、将__bridge_transfer改为__bridge,不转移对象的所有权。
2、去掉CFRelease(cfString)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的...
    卑微的戏子阅读 619评论 0 1
  • 设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的...
    iOS菜鸟大大阅读 700评论 0 1
  • ARC自动管理引用计数 ARC介绍 ARC其实也是基于引用计数,只是编译器在编译时期自动在已有代码中插入合适的内存...
    一直很安静_25ae阅读 961评论 0 1
  • 各位亲爱的死磕小伙伴们,大家下午好,我是来自智组的吴雯雯,很高兴今天由我给大家做一期管理时间管理工具的分享。...
    雯_wen阅读 207评论 0 0