一鸥诽、問(wèn)題描述
// 設(shè)置輸入最大字?jǐn)?shù)長(zhǎng)度限制
- (void)setInputLimitMaxLength:(NSUInteger)inputLimitMaxLength
{
objc_setAssociatedObject(self,
@selector(checkAndFilterBeyondLimitsCharacters),
@(inputLimitMaxLength),
OBJC_ASSOCIATION_ASSIGN);
}
// 獲取輸入最大字?jǐn)?shù)長(zhǎng)度限制
- (NSUInteger)getInputLimitMaxLength
{
return [objc_getAssociatedObject(self, @selector(checkAndFilterBeyondLimitsCharacters)) unsignedIntegerValue];
}
ARC模式下踏枣,在上述設(shè)置輸入字?jǐn)?shù)長(zhǎng)度限制方法setInputLimitMaxLength:
方法中聋溜,objc_AssociationPolicy類(lèi)型我設(shè)置的是OBJC_ASSOCIATION_ASSIGN
捏浊。
- 32位iphone機(jī)器上inputLimitMaxLength傳15時(shí)酥郭,調(diào)用
getCurrentInputLimitMaxLength
方法時(shí)直接崩潰EXC_BAD_ACCESS
,報(bào)錯(cuò):***\** -[CFNumber retain]: message sent to deallocated instance 0x7c3d9850**
愿吹,可看出self綁定的@(inputLimitMaxLength)
已經(jīng)釋放不从,野指針訪(fǎng)問(wèn)崩潰;但是inputLimitMaxLength傳6時(shí)調(diào)用方法運(yùn)行正常犁跪。 - 64位iphone機(jī)器上inputLimitMaxLength傳15或6時(shí)調(diào)用
getCurrentInputLimitMaxLength
方法運(yùn)行正常椿息,這是啥情況,懵逼了是不是坷衍?
二寝优、尋找原因
創(chuàng)建取值-16~16的NSNumber實(shí)例對(duì)象,在不同的視圖控制器(UIViewController)上運(yùn)行如下代碼枫耳,打印內(nèi)存地址發(fā)現(xiàn):
for (int i = -16; i <= 16; i++) {
for (int j = 0; j < 2; j++) {
NSLog(@"%d:%p", i, [NSNumber numberWithInteger:i]);
}
}
(1) 32位機(jī)器上結(jié)果如下:
-1~12內(nèi)存地址是一樣的乏矾,創(chuàng)建的實(shí)力對(duì)象存儲(chǔ)在內(nèi)存共享區(qū),永遠(yuǎn)不會(huì)被銷(xiāo)毀迁杨。而只要大于12或小于-1就是正常的創(chuàng)建在堆上的對(duì)象钻心,系統(tǒng)根據(jù)引用計(jì)數(shù)管理對(duì)象是否回收。截圖如下
(2) 64位機(jī)器上結(jié)果如下:
-16~16內(nèi)存地址是一樣的铅协,創(chuàng)建的實(shí)力對(duì)象存儲(chǔ)在內(nèi)存共享區(qū)捷沸,永遠(yuǎn)不會(huì)被銷(xiāo)毀。截圖如下
可見(jiàn):ARC模式下是系統(tǒng)在32bit設(shè)備上對(duì)NSNumber
類(lèi)型的對(duì)象做的優(yōu)化不夠徹底狐史,然后我們?cè)谑褂藐P(guān)聯(lián)對(duì)象時(shí)內(nèi)存修飾符又使用不當(dāng)痒给,造成了崩潰的問(wèn)題。猜測(cè)對(duì)于32bit的設(shè)備骏全,如同時(shí)存在大量的共享內(nèi)存會(huì)比較消耗資源苍柏,因此只對(duì)-1~12這少數(shù)的幾個(gè)數(shù)做了優(yōu)化,而出問(wèn)題時(shí)候我們傳入的參數(shù)剛好大于12姜贡,所以就掉進(jìn)了坑里序仙。而64bit設(shè)備存放在常量區(qū)的正常范圍區(qū)間比32bit大,所以沒(méi)有Crash鲁豪。
三潘悼、解決辦法以及結(jié)論
將OBJC_ASSOCIATION_ASSIGN
改為OBJC_ASSOCIATION_RETAIN
律秃,這樣對(duì)被綁定的NSNumber實(shí)例對(duì)象有一個(gè)強(qiáng)引用,被關(guān)聯(lián)綁定的對(duì)象就不會(huì)釋放治唤,在沒(méi)解除綁定時(shí)生命周期和綁定源(self)對(duì)象相同了棒动。因此,我認(rèn)為既然被關(guān)聯(lián)的都是對(duì)象宾添,那么絕大部分時(shí)候都應(yīng)該使用OBJC_ASSOCIATION_RETAIN
船惨,所以除了一些特殊情況外,運(yùn)行時(shí)關(guān)聯(lián)對(duì)象修飾符建議使用OBJC_ASSOCIATION_RETAIN
缕陕。