一. Tagged Pointer應用場景
ViewController
@interface ViewController ()
@property (strong, nonatomic) NSString *name;
@end
以下2段代碼能發(fā)生什么事铃剔?有什么區(qū)別檀葛?
1. 片段1
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abcfdfdgfdgdffd"];
});
}
2. 片段2
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abc"];
});
}
結論:
-
片段1
執(zhí)行會引起異常麦备,片段2正常執(zhí)行逃默。 -
片段1
是并發(fā)給name
屬性賦值虾宇,就是同時很多個線程訪問name的set方法
搓彻,因為name
是使用nonatomic
修飾的,不是線程安全的,相當于同時訪問以下代碼嘱朽,可能導致多次釋放name
旭贬,所以會拋異常。
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name retain];
}
}
解決方法:
a) 使用atomic
修飾name
屬性
b) 在dispatch_async
里邊加鎖
c) 使用串行隊列
- 片段2是使用的Tagged Pointer技術搪泳,直接將數據存儲在指針當中稀轨,所以
self.name
根本不存在釋放堆空間內存的操作,所以不會有問題岸军。
二. Tagged Pointer介紹
- 從64bit開始奋刽,iOS引入了Tagged Pointer技術瓦侮,用于優(yōu)化NSNumber、NSDate佣谐、NSString等小對象的存儲
- 在沒有使用Tagged Pointer之前肚吏, NSNumber等對象需要動態(tài)分配內存、維護引用計數等狭魂,NSNumber指針存儲的是堆中NSNumber對象的地址值
- 使用Tagged Pointer之后罚攀,NSNumber指針里面存儲的數據變成了:Tag + Data,也就是將數據直接存儲在了指針中
- 當指針不夠存儲數據時雌澄,才會使用動態(tài)分配內存的方式來存儲數據
- objc_msgSend能識別Tagged Pointer斋泄,比如NSNumber的intValue方法,直接從指針提取數據镐牺,節(jié)省了以前的調用開銷
- 如何判斷一個指針是否為Tagged Pointer是己?
a) iOS平臺,最高有效位是1(第64bit)
b) Mac平臺任柜,最低有效位是1