我們先來(lái)看一下基本的修飾符
atomic
設(shè)置@property屬性時(shí),默認(rèn)為atomic,提供多線程安全
在多線程環(huán)境下,原子操作是必要的,否則有可能引起錯(cuò)誤的結(jié)果。加了atomic,setter函數(shù)會(huì)變成這樣:
{lock}
if (property != newValue)
{ [property release];
property = [newValue retain]; }
{unlock}
對(duì)setter方法加了互斥鎖@synchronzied(鎖對(duì)象)
nonatomic
禁止多線程,變量保護(hù),提高性能
atomic是Objc使用的一種線程保護(hù)技術(shù),基本上來(lái)講,是防止在寫(xiě)未完成的時(shí)候被另外一個(gè)線程讀取,從而造成數(shù)據(jù)錯(cuò)誤。而這種機(jī)制是耗費(fèi)系統(tǒng)自痛的,所以在iPhone這種小型設(shè)備上,如果沒(méi)有使用多線程之間通訊編程,那么最好使用nonatomic
assign
對(duì)基礎(chǔ)數(shù)據(jù)類型(NSInteger,CGFloat)和C數(shù)據(jù)類型(int,float)等
- assign在ARC和MRC中都是存在的
- assign一般用來(lái)修飾基本數(shù)據(jù)類型
- assign也可用來(lái)修飾對(duì)象,但是,對(duì)象的引用計(jì)數(shù)不+1
- assign如果用來(lái)修飾對(duì)象屬性,當(dāng)對(duì)象銷毀后之后指針不會(huì)指向nil,會(huì)出現(xiàn)野指針錯(cuò)誤(與weak的區(qū)別)
- MRC用assign來(lái)修飾代理,是為了防止循環(huán)引用
weak
- 弱指針是針對(duì)對(duì)象的修飾詞,就是說(shuō)他不能修飾基本數(shù)據(jù)類型
retain
對(duì)其他NSObject和其子類屬性進(jìn)行release舊值,再retain新值
指定retain會(huì)在賦值時(shí)喚醒傳入值的retain消息,此屬性只能用于OC對(duì)象類型,而不能用于Core Foundation對(duì)象,原因在于retain操作會(huì)增加對(duì)象的引用計(jì)數(shù)+1,而基本數(shù)據(jù)類型和Core Foundation對(duì)象都沒(méi)有引用計(jì)數(shù)。在非ARC環(huán)境下,你需要自己retain一個(gè)想要保持的對(duì)象。ARC環(huán)境下就不需要了。現(xiàn)在唯一要做的就是用一個(gè)指針指向這個(gè)對(duì)象,只要指針沒(méi)有被重置為空,對(duì)象就會(huì)一直在堆上。當(dāng)指針指向新值的時(shí)候,原來(lái)的對(duì)象就會(huì)被release一次。這對(duì)實(shí)例變量,synthesize的變量或者是局部變量都是實(shí)用的。
copy
一般NSString或者block用copy修飾
首先, block是一個(gè)對(duì)象, 所以block理論上是可以retain/release的. 但是block在創(chuàng)建的時(shí)候它的內(nèi)存是默認(rèn)是分配在棧(stack)上, 而不是堆(heap)上的. 所以它的作用域僅限創(chuàng)建時(shí)候的當(dāng)前上下文(函數(shù), 方法...), 當(dāng)你在該作用域外調(diào)用該block時(shí), 程序就會(huì)崩潰.

Apple官方文檔
意思就是 : 一般情況下你不需要自行調(diào)用copy或者retain一個(gè)block. 只有當(dāng)你需要在block定義域以外的地方使用時(shí)才需要copy. Copy將block從內(nèi)存棧區(qū)移到堆區(qū).
其實(shí)block使用copy是MRC留下來(lái)的也算是一個(gè)傳統(tǒng)吧, 在MRC下, 如上述, 在方法中的block創(chuàng)建在棧區(qū), 使用copy就能把他放到堆區(qū), 這樣在作用域外調(diào)用該block程序就不會(huì)崩潰. 但在ARC下, 使用copy與strong其實(shí)都一樣, 因?yàn)閎lock的retain就是用copy來(lái)實(shí)現(xiàn)的
。
copy 是對(duì)引用對(duì)象進(jìn)行copy操作,生成了一個(gè)新的對(duì)象,新對(duì)象的引用計(jì)數(shù)為1,原來(lái)的引用對(duì)象引用計(jì)數(shù)不變,這里我們不難發(fā)現(xiàn)copy和retain的區(qū)別:
copy其實(shí)是建立了一個(gè)全新的對(duì)象,原來(lái)對(duì)象的引用計(jì)數(shù)不變,retain是對(duì)原有的對(duì)象再次的強(qiáng)引用,對(duì)象引用計(jì)數(shù)+1
舉例說(shuō)明:
1.比如一個(gè)NSString 對(duì)象,地址為0×1111 ,內(nèi)容為@”STR”,Copy 到另外一個(gè)NSString 之后,地址為0×2222 ,內(nèi)容相同。
2.新的對(duì)象retain為1 ,舊有對(duì)象沒(méi)有變化retain 到另外一個(gè)NSString 之后,地址相同(建立一個(gè)指針,指針拷貝),內(nèi)容當(dāng)然相同,這個(gè)對(duì)象的retain值+1。
總結(jié):retain 是指針拷貝,copy 是內(nèi)容拷貝。
大家可以打印對(duì)象的地址和變量自身的地址
NSString *mstr = @"123";//如果字符串是NSString類型,copy還是strong 他返回的都是不可變類型,如果是NSMutableString類型,對(duì)其中任何一個(gè)重新賦值,會(huì)產(chǎn)生新的內(nèi)存地址,所以他改變,對(duì)另外的對(duì)象沒(méi)有影響,用strong是對(duì)其指針再次引用,retainCount+1,用copy則是深復(fù)制,和源頭互相獨(dú)立,互不影響
self.rstr = mstr;
self.cstr = mstr;
//基礎(chǔ)數(shù)據(jù)類型在棧上,對(duì)象在堆上
NSLog(@"mStr:%p,%p", mstr,&mstr);
NSLog(@"copyStr:%p,%p", _cstr, &_cstr);
NSLog(@"retainStr:%p,%p", _rstr, &_rstr);
NSLog(@"%@=========%@========%@",mstr,self.rstr,self.cstr);
/**
假如,mStr對(duì)象的地址為0x11,也就是0x11是@“abc”的首地址,mStr變量自身在內(nèi)存中的地址為0x123;
當(dāng)把mStr賦值給retain的rStr時(shí),rStr對(duì)象的地址為0x11,rStr變量自身在內(nèi)存中的地址為0x124;rStr與mStr指向同樣的地址,他們指向的是同一個(gè)對(duì)象@“abc”,這個(gè)對(duì)象的地址為0x11,所以他們的值是一樣的。
當(dāng)把mStr賦值給copy的cStr時(shí),cStr對(duì)象的地址為0x22,cStr變量自身在內(nèi)存中的地址0x125;cStr與mStr指向的地址是不一樣的,他們指向的是不同的對(duì)象,所以copy是深復(fù)制,一個(gè)新的對(duì)象,這個(gè)對(duì)象的地址為0x22,值為@“abc”。
*/
mstr = @"234";//重新賦值,會(huì)發(fā)現(xiàn)mstr本身在內(nèi)存中的地址沒(méi)有變,還是指向mstr,但是他的值地址發(fā)生改變了,
NSLog(@"mStr:%p,%p", mstr,&mstr);
NSLog(@"copyStr:%p,%p", _cstr, &_cstr);//前一個(gè)打印的地址是cstr這個(gè)變量的 值 的內(nèi)存地址,即對(duì)值的引用,后一個(gè)打印的地址是cstr這個(gè)變量自身的內(nèi)存地址
NSLog(@"retainStr:%p,%p", _rstr, &_rstr);
NSLog(@"%@=========%@========%@",mstr,self.rstr,self.cstr);
這里來(lái)解釋一下為什么字符串用copy而不用strong
對(duì)于字符串,我們希望是一次內(nèi)容的拷貝,也就是說(shuō)拷貝出來(lái)的字符串對(duì)象和愿字符串對(duì)象相互獨(dú)立,沒(méi)有任何關(guān)系,這樣,外部修改拷貝的字符串也就不會(huì)影響我們?cè)瓉?lái)的字符串的值
const
變量修飾符,只有只讀權(quán)限
register
變量名前加register修飾,編譯器會(huì)優(yōu)先將此變量放在寄存器中,這樣對(duì)這個(gè)變量進(jìn)行的各種操作及運(yùn)算會(huì)很快。當(dāng)然CPU周邊的用戶可用空閑寄存器是有限的,所以當(dāng)定義多個(gè)register修飾的變量后,當(dāng)可用寄存器用完之后,依然是在普通的內(nèi)存中為變量開(kāi)辟空間
static
有時(shí)候我們非常希望,用一個(gè)小變量記錄某函數(shù)調(diào)用的次數(shù),解決這個(gè)問(wèn)題
方法1.可以使用全局變量,但是由于所有函數(shù)都可以修改他,對(duì)于較大程序出了問(wèn)題不好調(diào)試,所以使用全局變量并不好
方法2.可以在目標(biāo)函數(shù)中定義一個(gè)static變量,每次進(jìn)入函數(shù)讓其++,static作用在局部變量前,函數(shù)結(jié)束此變量的值不清空,即改變了此變量的生命期,而且直到整個(gè)程序結(jié)束,并且此變量的值只有在定義他的函數(shù)體內(nèi)被使用和重新賦值
一般有如下作用:
- 函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,不同于auto變量,該變量的內(nèi)存只分配一次,因此其值在下次調(diào)用時(shí)仍維持上次的值;
- 在模塊內(nèi)的static全局變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外的其他函數(shù)訪問(wèn)
- 在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其他函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明他的模塊內(nèi)
- 在類中的static成員變量屬于整個(gè)類所擁有,對(duì)類的所有對(duì)象只有一份拷貝
- 在類中的static成員函數(shù)屬于整個(gè)類所有,這個(gè)函數(shù)不接受this指針,因而只能訪問(wèn)類的static成員變量
extern
extern int n;
extern可以擴(kuò)展全局變量或函數(shù)的作用范圍,只有全局變量或函數(shù)才可以用extern擴(kuò)展
extern可以擴(kuò)展函數(shù)的作用范圍,可以跨文件擴(kuò)展,前提是被擴(kuò)展的全局變量或者函數(shù)在定義時(shí)沒(méi)有被statci修飾
擴(kuò)展
1.ARC環(huán)境下。strong代替了retain,weak代替assign
2.weak的作用,在ARC環(huán)境下,所有指向這個(gè)對(duì)象的weak指針都將被置為nil,。這個(gè)特性很有用,相信很多開(kāi)發(fā)者都被指針指向已釋放的對(duì)象所造成的EXC_BAD_ACCESS困擾過(guò),使用ARC以后,不論是strong還是weak類型的指針,都不會(huì)再指向一個(gè)已經(jīng)銷毀的對(duì)象,從根本上解決了意外釋放導(dǎo)致的crash
3.assign的作用,簡(jiǎn)單賦值(指針賦值),不改變引用計(jì)數(shù),對(duì)基礎(chǔ)數(shù)據(jù)類型(NSIntefer,CGFloat)和C數(shù)據(jù)類型(int,float,double,char)等,
4.strong的作用,在ARC環(huán)境下,只要某一個(gè)對(duì)象被一個(gè)strong指針指向,該對(duì)象就不會(huì)被銷毀,如果對(duì)象沒(méi)有被任何strong指針指向,那么就會(huì)被銷毀,在默認(rèn)情況下,所有的實(shí)例變量和局部變量都是strong類型
5.__weak, __unsafe_unretained, __autoreleasing,的區(qū)別
__weak:聲明了一個(gè)可以自動(dòng) nil 化的弱引用。 __unsafe_unretained:聲明一個(gè)弱應(yīng)用,但是不會(huì)自動(dòng)nil化,也就是說(shuō),如果所指向的內(nèi)存區(qū)域被釋放了,這個(gè)指針就是一個(gè)野指針了。 __autoreleasing:用來(lái)修飾一個(gè)函數(shù)的參數(shù),這個(gè)參數(shù)會(huì)在函數(shù)返回的時(shí)候被自動(dòng)釋放。
自動(dòng)引用計(jì)數(shù)
Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.
ARC是一個(gè)編譯器特性,提供了對(duì)iOS對(duì)象的自動(dòng)內(nèi)存管理,ARC在編譯期間自動(dòng)在適當(dāng)?shù)牡胤教砑覱bjc對(duì)象的retain和release操作代碼,而不需要我們?nèi)リP(guān)心。從概念上來(lái)說(shuō),ARC與手動(dòng)計(jì)數(shù)內(nèi)存管理遵循相同的內(nèi)存管理法則,但是ARC也無(wú)法防止循環(huán)強(qiáng)引用
ARC引入了新的修飾符來(lái)修飾變量和聲明變量
- 聲明變量的修飾符:__strong,__weak,__unsafe_unretained,__autoreleasing;
- 聲明屬性的修飾符:strong,weak,unsafe_unretained
對(duì)象和Core Foundation-style對(duì)象直接的轉(zhuǎn)換修飾符符號(hào):__bridge,__bridge_retained或CFBridgingRetain,__bridge_transfer或CFBridgingRelease - 對(duì)于線程的安全,有nonatomic,這樣效率就更高了,但是不是線程的,如果要線程安全,可以使用atomic,這樣在訪問(wèn)時(shí)會(huì)有線程鎖
- 記住內(nèi)存管理法則:誰(shuí)使對(duì)象的引用計(jì)數(shù)+1,不再引用時(shí),誰(shuí)就負(fù)責(zé)將該對(duì)象的引用計(jì)數(shù)-1
參考資料
[http://blog.csdn.net/woaifen3344/article/details/50219177]
[http://blog.csdn.net/u011366778/article/details/47088251]
[http://blog.csdn.net/ios_hc/article/details/51933174]