iOS編程中,定義屬性中的特性有atomic嘿般、nonatomic段标、copy、assign炉奴、strong逼庞、weak等,一般格式如下:
@property (nonatomic, strong) NSString *name;
下面詳細解釋一下他們的區(qū)別盆佣。
atomic
- 默認屬性往堡。
- 當前進程進行到一半,其他線程來訪問當前線程共耍,可以保證先執(zhí)行完畢當前線程。
- 只是保證setter/getter 完整吨瞎,不是線程安全痹兜。
例如:對于atomic的對象,線程A調(diào)用getter颤诀,同時線程B字旭、線程C都調(diào)用setter并設(shè)不同的值,最后線程A可能得到原來的值崖叫、也可能得到線程B遗淳、線程C設(shè)的值,只能夠保證得到的是原始值心傀、B線程設(shè)定的值屈暗、C線程設(shè)定的值三者中一個完整值,沒有辦法確定最終得到的是哪個值脂男。如果線程D調(diào)用release养叛,程序會崩潰。所以atomic只是read/write安全宰翅,不是thread安全弃甥。
Runtime objc-accessors.mm文件包含了屬性設(shè)值、取值源碼汁讼,如下所示:
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
可以看到淆攻,atomic
修飾的設(shè)值、取值方法使用了自旋鎖嘿架,確保線程同步瓶珊。
雖然設(shè)值、取值方法是原子操作眶明,但不代表是線程安全艰毒。例如,可變數(shù)組使用atomic
修飾搜囱,只是取數(shù)組丑瞧、設(shè)置數(shù)組是原子操作柑土,但操作數(shù)組元素不再是線程安全。
nonatomic
- 非默認屬性绊汹。
- 兩個線程同時訪問同一個屬性將會導(dǎo)致無法預(yù)計的結(jié)果稽屏。
- 優(yōu)點是程序運行速度快。
copy
- 是owner西乖,不是reference(引用)狐榔。當對象可變時,可設(shè)置為copy获雕,用于獲取此時值的副本薄腻。
- 新的對象引用計數(shù)為1,與原始對象引用計數(shù)無關(guān)届案,且原始對象引用計數(shù)不會改變庵楷。
- 使用copy創(chuàng)建的新對象也是強引用,使用完成后需要負責釋放該對象楣颠。
- copy特性可以減少對象對上下文的依賴尽纽。新對象、原始對象中任一對象的值改變不會影響另一對象的值童漩。
- 要想設(shè)置該對象的特性為copy弄贿,該對象必須遵守
NSCopying
協(xié)議,F(xiàn)oundation類默認實現(xiàn)了NSCopying
協(xié)議矫膨,所以只需要為自定義的類實現(xiàn)該協(xié)議即可差凹。更全面了解NSCopying
協(xié)議,查看 深復(fù)制豆拨、淺復(fù)制直奋、copy、mutableCopy 一文施禾。
assign
- 與copy相反脚线,只是reference,不是owner弥搞。只返回指針邮绿。
- 用于float、int攀例、BOOL等類型船逮。
- 釋放后再發(fā)送消息會導(dǎo)致程序崩潰。
strong
- 默認屬性
- strong = retain iOS引入ARC后粤铭,用strong替代了retain挖胃。
- 創(chuàng)建一個強引用的指針,引用對象引用計數(shù)加1。
- strong特性表示兩個對象內(nèi)存地址相同(建立一個指針酱鸭,進行指針拷貝)吗垮,內(nèi)容會一直保持相同,直到更改一方內(nèi)存地址凹髓,或?qū)⑵湓O(shè)置為
nil
烁登。 - 如果有多個對象同時引用一個屬性,任一對象對該屬性的修改都會影響其他對象獲取的值蔚舀。
- 所有實例變量饵沧、局部變量默認都是strong。
weak
- 只是reference赌躺,不是owner狼牺。即引用計數(shù)不會加1。
- 可將weak對象設(shè)為nil寿谴,向nil發(fā)送消息锁右,什么都不會執(zhí)行,程序也不會崩潰讶泰。
- 代理使用weak。delegate幾乎一直own代理對象拂到,所以代理對象應(yīng)該對代理使用weak痪署,否則會形成循環(huán)引用(retain cycle)。但也有例外兄旬,如果代理對象的生命周期比代理短狼犯,代理對象也可以使用strong。
- IBOutlet常用weak领铐。
關(guān)于strong和weak對比的一個形象例子:
假設(shè)對象是一條小狗悯森,小狗想跑走(be deallocated)。
strong類型就像是拴狗的繩子绪撵,只要有一條繩子栓住狗瓢姻,它就不能跑走,如果有五條繩子拴著同一條狗(五個strong類型指向同一個對象)音诈,只有當五條繩子都釋放狗才可以跑走幻碱。
weak類型就像是小孩子看著小狗說:看這里有小狗。只要還有繩子拴著小狗细溅,小孩子們就可以繼續(xù)指著小狗說:看這里有小狗褥傍。當繩子釋放了的時候,不管有多少小孩子依舊在指著小狗說:看這里的小狗喇聊。小狗都會跑掉恍风。
當最后一個strong指針不再指向這個對象,這個對象就會被釋放,此時朋贬,所有指向這個對象的weak指針都將被清空凯楔。
readonly
- 非默認屬性
- 只有可讀方法,也就是只有g(shù)etter方法兄世。
readwrite
- 默認屬性
- 如果希望一個屬性只允許自己讀寫啼辣,而對所有外部文件都是只讀的,可以在接口部分聲明該屬性為readonly類型御滩,最后在私有接口部分重寫該屬性為readwrite類型鸥拧。