Skip to content

Commit fada542

Browse files
committed
add post
1 parent 4d5755d commit fada542

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
layout: post
3+
title: 从一道网易面试题浅谈 Tagged Pointer
4+
subtitle: 浅谈 Tagged Pointer
5+
date: 2017-12-26
6+
author: BY
7+
header-img: img/post-bg-universe.jpg
8+
catalog: true
9+
tags:
10+
- iOS
11+
---
12+
13+
14+
## 前言
15+
16+
这篇博客九月就想写了,因为赶项目拖了到现在,抓住17年尾巴写吧~
17+
18+
19+
## 正文
20+
21+
上次看了一篇 [《从一道网易面试题浅谈OC线程安全》](https://www.jianshu.com/p/cec2a41aa0e7) 的博客,主要内容是:
22+
23+
作者去网易面试,面试官出了一道面试题:下面代码会发生什么问题?
24+
25+
```objc
26+
@property (nonatomic, strong) NSString *target;
27+
//....
28+
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
29+
for (int i = 0; i < 1000000 ; i++) {
30+
dispatch_async(queue, ^{
31+
self.target = [NSString stringWithFormat:@"ksddkjalkjd%d",i];
32+
});
33+
}
34+
```
35+
36+
答案是:会 crash。
37+
38+
我们来看看对`target`属性(`strong`修饰)进行赋值,相当与 MRC 中的
39+
40+
```
41+
- (void)setTarget:(NSString *)target {
42+
if (target == _target) return;
43+
id pre = _target;
44+
[target retain];//1.先保留新值
45+
_target = target;//2.再进行赋值
46+
[pre release];//3.释放旧值
47+
}
48+
```
49+
50+
因为在 *并行队列* `DISPATCH_QUEUE_CONCURRENT`*异步* `dispatch_async``target`属性进行赋值,就会导致 target 已经被 `release`了,还会执行 `release`。这就是向已释放内存对象发送消息而发生 crash 。
51+
52+
53+
### 但是
54+
55+
我敲了这段代码,执行的时候发现并不会 crash~
56+
57+
```objc
58+
@property (nonatomic, strong) NSString *target;
59+
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
60+
for (int i = 0; i < 1000000 ; i++) {
61+
dispatch_async(queue, ^{
62+
// ‘ksddkjalkjd’删除了
63+
self.target = [NSString stringWithFormat:@"%d",i];
64+
});
65+
}
66+
```
67+
68+
原因就出在对 `self.target` 赋值的字符串上。博客的最后也提到了 - *‘上述代码的字符串改短一些,就不会崩溃’*,还有 `Tagged Pointer` 这个东西。
69+
70+
我们将上面的代码修改下:
71+
72+
73+
```objc
74+
NSString *str = [NSString stringWithFormat:@"%d", i];
75+
NSLog(@"%d, %s, %p", i, object_getClassName(str), str);
76+
self.target = str;
77+
```
78+
79+
输出:
80+
81+
```
82+
0, NSTaggedPointerString, 0x3015
83+
```
84+
85+
发现这个字符串类型是 `NSTaggedPointerString`,那我们来看看 Tagged Pointer 是什么?
86+
87+
### Tagged Pointer
88+
89+
Tagged Pointer 详细的内容可以看这里 [深入理解Tagged Pointer](http://www.infoq.com/cn/articles/deep-understanding-of-tagged-pointer)。
90+
91+
Tagged Pointer 是一个能够提升性能、节省内存的有趣的技术。
92+
93+
- Tagged Pointer 专门用来存储小的对象,例如 **NSNumber** 和 **NSDate**(后来可以存储小字符串)
94+
- Tagged Pointer 指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。
95+
- 它的内存并不存储在堆中,也不需要 malloc 和 free,所以拥有极快的读取和创建速度。
96+
97+
98+
99+
100+
### 参考:
101+
102+
- [从一道网易面试题浅谈OC线程安全](https://www.jianshu.com/p/cec2a41aa0e7)
103+
104+
- [深入理解Tagged Pointer](http://www.infoq.com/cn/articles/deep-understanding-of-tagged-pointer)
105+
106+
- [【译】采用Tagged Pointer的字符串](http://www.cocoachina.com/ios/20150918/13449.html)
107+

0 commit comments

Comments
 (0)