Objective-C Objective-C中的指標,及對象的直接指向,copy和mutablecopy

來源:互聯網
上載者:User

標籤:

1.Objective-C的指標世界

OC一直是人感覺比較變態的一門語言,為什麼呢?因為它的每個變數都是指標型,多的都幾乎讓人忘了那個*的存在了。

所以常常a=b這個等號讓我產生錯覺,總以為a從b那拷貝了一份。

然而這的的確確,卻是個指標。a這個變數存的內容是b所在的地址。

比如我定義了一個Student的Class,new了stu1和stu2,並把stu2=stu1,那當兩者任何一個進行修改時,兩個變數的內容都會修改。

    Student *stu1=[[Student alloc]init];    [email protected]"stu1";    Student *stu2=stu1;    [email protected]"stu2";    NSLog(@"STU1:%@----STU2:%@",stu1.name,stu2.name);//輸出兩個都是stu2

在C/C++語言裡,不習慣用指標作變數的情況下,當然兩者是不一樣的,實際上=等號是做了一份拷貝。

    Student stu1;    stu1.name="stu1";    Student stu2=stu1;    stu2.name="stu2";    cout<<"stu1:"<<stu1.name<<" stu2:"<<stu2.name<<endl;//輸出前者stu1,後者stu2

 但是上面的情況建立的是C/C++語言裡所謂的棧對象,但棧的大小很有限,在建立堆對象(指標對象)的情況下,就和OC十分相似了

(然而教科書裡教我們建立的貌似都是棧對象)

    Student *stu1= new Student();    stu1->name="stu1";        Student *stu2=stu1;    stu2->name="stu2";    cout<<"stu1:"<<stu1->name<<" stu2:"<<stu2->name<<endl;//輸出兩個都是stu2

 在Java裡面,雖然變數的建立前面沒有*,但其實預設產生的也是堆對象,對象給變數賦值只是一個引用。

 

2.NSString的錯覺

 但是對NSString,我們容易產生錯覺,比如我這樣寫:

    NSString *[email protected]"str1";    NSString *str2=str1;    [email protected]"str2";    NSLog(@"str1:%@----str2:%@",str1,str2);//輸出前者str1,後者str2

 為毛str2的修改還是不影響str1呢?說好的指標呢?這是因為通過[email protected]""方式賦值,事實上已經重新開闢了記憶體,然後讓str2指向這個新地方,所以str2的修改肯定就不會影響str1。

可以通過輸出指標所在地址和指標指向地址來進行分析:

    NSString *[email protected]"str1";    NSString *str2=str1;    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指標地址,顯示不一樣,這是兩個不一樣的指標    NSLog(@"str1:%p----str2:%p",str1,str2);//內容地址,顯示一樣,說明都指向@“str1”        [email protected]"str2";    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指標地址,顯示不一樣,這是兩個不一樣的指標    NSLog(@"str1:%p----str2:%p",str1,str2);//內容地址,顯示不一樣,說明str1所指內容不變,str2所指內容已經變化        NSLog(@"str1:%@----str2:%@",str1,str2);//輸出前者str1,後者str2

以下的方法,實際上也都並不能拷貝一份,因為編譯器對此做了最佳化,使幾個指標變數指向的同一個記憶體地區

    NSString *[email protected]"hello";    NSString *string2 = [[NSString alloc]initWithString:string1];      NSString *string3 = [NSString stringWithString:string1];

可見,NSString類變數都是遵循這樣的準則:"指標A賦值給指標B,兩者指向同一塊記憶體,修改後重新指向開闢新記憶體",

 

3.到底有沒有拷貝?淺拷貝?深拷貝?

(1)NSString到NSString的copy:(編譯器做了最佳化,其實並無copy,跟直接指向是一樣的)

即便是通過以下的Copy,實際上和上面的情況一樣,也只是把str1指向地址拷貝給了str2,使它們指向了同一個@"str1"

    NSString *[email protected]"aaa";    NSString *str2=[str1 copy];    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指標地址輸出,不一樣,說明指標建立了    NSLog(@"str1:%p----str2:%p",str1,str2);//指標指向內容地址輸出,是一樣的,說明內容沒有被拷貝

所以,在NSString給NSString賦值時,雖然地址一樣,但一旦修改就會重新指向,所以任何方式相互都不會產生幹擾,以下方法都是等價的,並不一定樣要copy,其實直接用第一種方式比較快。

  NSString *str2=str1;
  NSString *str3 = [[NSString alloc]initWithString:str1];
  NSString *str4 = [NSString stringWithString:str1];
NSString *str5 = [str1 copy];

如果情境需要,比如為了讓某個str1指向的地方銷毀,要先拷貝到新地址,然後用str2指,可以對NSString進行拷貝。

(2)NSString到NSString的拷貝:

    NSString *[email protected]"aaa";    NSString *str2=[str1 mutableCopy];    NSLog(@"str1:%p----str2:%p",&str1,&str2);//指標地址輸出,不一樣,說明指標建立了    NSLog(@"str1:%p----str2:%p",str1,str2);//指標指向內容地址輸出,是不一樣的,說明重新開闢了記憶體,把str1的內容拷貝到新記憶體,str2變數指向這個新地址

 

(3)NSMutableString到NSString的直接指向:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];    NSString *str=mStr;    NSLog(@"mstr:%p-----str:%p",mStr,str);//指標指向內容地址一樣,說明mStr的改變會聯動str    [mStr appendString:@"def"];    NSLog(@"mstr:%@-----str:%@",mStr,str);//mStr的改變影響了str

 這種情況,mStr的改變會影響str,但str改變就會重新指向,並不會影響mStr

(4)NSMutableString到NSString的拷貝:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];    NSString *str=[mStr copy];//NSString *str=[mStr mutableCopy];也能實現
    NSLog(@"mstr:%p-----str:%p",mStr,str);

如果不希望mStr改變影響str,可以對mStr的內容進行拷貝。

但這裡面,[mStr copy]和[mstr mutableCopy],雖然都對原mStr進行了拷貝,開闢了新記憶體地區,但區別在於前者拷貝的對象是不可變的,後者的是可變的。可變字串賦值給NSString其實也就喪失動態性了。

(5)NSMutableString到NSMutableString的指向:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];    NSMutableString *mStr2=mStr;    NSLog(@"mstr:%p-----mstr2:%p",mStr,mStr2);    [mStr appendString:@"def"];    NSLog(@"mstr:%@-----mstr2:%@",mStr,mStr2);

 這種情況當然是兩者改變都會互相影響了。

(6)NSMutableString到NSMutableString的拷貝:

    NSMutableString *mStr=[NSMutableString stringWithString:@"abc"];    NSMutableString *mStr2=[mStr mutableCopy];    NSLog(@"mstr:%p-----mstr2:%p",mStr,mStr2);//指標內容地址不一樣,說明實現了拷貝    [mStr2 appendString:@"def"];    NSLog(@"mstr:%@-----mstr2:%@",mStr,mStr2);//互不相干

 此種方式實現了對NSMutableString的拷貝,產生兩個互不相干的可變字串。

那如果通過copy來拷貝,返回不可變字串賦值給可變的mStr2會怎麼樣?

    NSMutableString *mStr2=[mStr copy];

 沒錯,會崩掉的。

同樣,用NSString給NSMutableString賦值的都是作死行為

    NSString *[email protected]"str1";    NSMutableString *mStr=[str1 copy];    [mStr appendFormat:@"abc"];

同樣崩。 

 

總結一下:

在NSString和NSMutableString中:

不變賦給不變,必須Mutablecopy才能完成真正的拷貝。

可變賦給不變,直接指向,不變會隨可變而變,copy和mutablecopy都能完成拷貝。

不變賦給可變,無論什麼指向拷貝方法都是作死行為,必須調stringWithString函數初始化

可變賦給可變,只有Mutablecopy才能真正的拷貝,copy作死。

 

Objective-C Objective-C中的指標,及對象的直接指向,copy和mutablecopy

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.