開發(fā)中使用屬性很頻繁,常見的屬性內(nèi)存管理語義主要有 strong、copy狭郑、weak腹暖、assign,本次主要介紹下 strong 和 copy愿阐。如果你了解了深淺拷貝微服,那這部分內(nèi)容應(yīng)該很容易理解;深淺拷貝的內(nèi)容可參考:iOS 你不一定了解的深淺拷貝
可以通過這樣一個場景缨历,理解 strong 和 copy 的本質(zhì)區(qū)別:
- 創(chuàng)建一個 Person 類以蕴,聲明兩個屬性,一個用 strong辛孵,另外一個用 copy;
#import <Foundation/Foundation.h>
@interface CHIPerson : NSObject
@property (nonatomic, strong) NSString *chi_strongName;
@property (nonatomic, copy) NSString *chi_copyName;
@end
- 下面在代碼中使用這個類丛肮,并對屬性賦值
NSString *string = @"123456";
NSLog(@"\nstring : %@-%p\n\n", string, string);
CHIPerson *person = [[CHIPerson alloc] init];
person.chi_strongName = string;
person.chi_copyName = string;
NSLog(@"\nstrong : %@-%p\ncopy : %@-%p\n\n", person.chi_strongName, person.chi_strongName, person.chi_copyName, person.chi_copyName);
// 改變字符串的內(nèi)容
string = @"789";
NSLog(@"\nstrong : %@-%p\ncopy : %@-%p\n\n", person.chi_strongName, person.chi_strongName, person.chi_copyName, person.chi_copyName);
NSLog(@"\nstring : %@-%p", string, string);
- 控制臺打印結(jié)果
打印結(jié)果顯示,使用 strong 和 copy 的屬性內(nèi)容相同魄缚,指向同一處內(nèi)存區(qū)域缔御,不可變字符串在重新賦值后榨汤,指向新的內(nèi)存區(qū)域,對兩個屬性值沒有什么影響;
到這里還沒有看出 strong 與 copy 有什么不同之處培遵,下面換種方式:
- 將不可變字符串換成可變字符串
NSMutableString *mutString = [NSMutableString stringWithFormat:@"123456"];
NSLog(@"\nstring : %@-%p\n\n", mutString, mutString);
CHIPerson *person = [[CHIPerson alloc] init];
person.chi_strongName = mutString;
person.chi_copyName = mutString;
NSLog(@"\nstrong : %@-%p\ncopy : %@-%p\n\n", person.chi_strongName, person.chi_strongName, person.chi_copyName, person.chi_copyName);
// 改變可變字符串的內(nèi)容
[mutString appendString:@"789"];
NSLog(@"\nstrong : %@-%p\ncopy : %@-%p\n\n", person.chi_strongName, person.chi_strongName, person.chi_copyName, person.chi_copyName);
NSLog(@"\nstring : %@-%p", mutString, mutString);
- 再看控制臺打印結(jié)果
這里就有明顯的不同了村砂,打印結(jié)果顯示保屯,使用 strong 的屬性內(nèi)容及地址與可變字符串保持一致辜膝,但是使用 copy 關(guān)鍵字的屬性內(nèi)容雖然相同,地址已經(jīng)改變了飞蛹;更改可變字符串的值后谤狡,strong 關(guān)鍵字的屬性值跟著發(fā)生了變化,而 copy 關(guān)鍵字的屬性值依然保持不變卧檐;
為什么會出現(xiàn)這樣差異墓懂,實(shí)際上,使用 copy 關(guān)鍵字的屬性霉囚,在做賦值操作的時候捕仔,會在 setter 方法中做一次 copy 操作:
- (void)setChi_copyName:(NSString *)chi_copyName
{
_chi_copyName = [chi_copyName copy];
}
這就是為什么很多有可變類型的屬性,要使用 copy 關(guān)鍵字盈罐;copy 關(guān)鍵字的屬性在做賦值操作時逻澳,不管傳入的類型是可變的還是不可變的,屬性本身相當(dāng)于持有一份不可變的副本暖呕,外部變量值更改時,不會對屬性產(chǎn)生影響苞氮,這樣可以有效保證屬性的封裝性湾揽;
這與深淺拷貝的原理是保持一致的:對不可變對象的 copy 操作,是淺拷貝;對可變對象的 copy 操作库物,是深拷貝霸旗;
到這里我們可以大膽做下嘗試,對 strong 關(guān)鍵字的屬性戚揭,實(shí)現(xiàn) copy 的特性诱告,即重寫 setter 方法:
- (void)setChi_strongName:(NSString *)chi_strongName
{
_chi_strongName = [chi_strongName copy];
}
- 再看控制臺打印結(jié)果
可以看出,strong 關(guān)鍵字聲明的屬性也有了 copy 的特性