為什么傳遞NSError需要指針的指針

在編寫(xiě)Objective-C代碼時(shí),很多時(shí)候會(huì)需要對(duì)錯(cuò)誤進(jìn)行處理,在OC里使用的是NSError。當(dāng)我們編寫(xiě)一個(gè)方法時(shí),比如進(jìn)行一個(gè)網(wǎng)絡(luò)請(qǐng)求,這個(gè)時(shí)候會(huì)有請(qǐng)求成功或請(qǐng)求失敗兩種情況。當(dāng)請(qǐng)求失敗時(shí),我們會(huì)在方法中生成一個(gè)錯(cuò)誤并告訴調(diào)用方。

在C語(yǔ)言里,返回?cái)?shù)據(jù)有兩種方式,一種是常用的return返回,這是大部分情況下從函數(shù)返回?cái)?shù)據(jù)的方式,但C語(yǔ)言里一個(gè)函數(shù)只能返回一個(gè)數(shù)據(jù),也就是return后面只能有一個(gè)指針或值(包括結(jié)構(gòu)體)。如果想要返回多個(gè)數(shù)據(jù)時(shí),有時(shí)會(huì)考慮使用參數(shù)返回的形式。

最典型的例子就是交換兩個(gè)數(shù)值的函數(shù):

int a = 1, b = 2;
swap(&a, &b);

void swap(int *a, int *b) {
   int tmp = *a; *a = *b; *b = tmp; //或者直接*a ^= *b ^= *a ^= *b;
}

交換外部變量的方式很多,如指針、引用、位運(yùn)算,但不能直接使用變量,這是因?yàn)樾螀⒑蛯?shí)參的區(qū)別,具體不用多說(shuō)。此處想強(qiáng)調(diào)的是,不使用return語(yǔ)句,返回兩個(gè)交換后的變量值,可以使用這種參數(shù)指針的形式。

鋪墊這些,是為了說(shuō)明NSError的使用情況。在OC中錯(cuò)誤生成的常見(jiàn)形式是這樣:

-(id)requestWithParameter:(id)obj error:(NSError *__autoreleasing *)error {
   id result = ... //使用obj參數(shù)進(jìn)行網(wǎng)絡(luò)請(qǐng)求并返回
   if (result != nil) {
      return result;
   } else {
      if (error != NULL) {//判斷調(diào)用方是否需要獲取錯(cuò)誤信息
         *error = [NSError errorWithDomain:...]; //生成錯(cuò)誤對(duì)象
      }
      return nil;
   }
}

對(duì)比發(fā)現(xiàn),交換指針的方法使用的是單指針作為參數(shù),直接交換了指針指向的內(nèi)容;而錯(cuò)誤生成的案例中,錯(cuò)誤參數(shù)使用的是指針的指針。

實(shí)際上,他們的本質(zhì)是一樣的。

我們先考慮這種情況:

-(id)requestWithParameter:(id)obj error:(NSError __autoreleasing *)error { 
   id result = ... //使用obj參數(shù)進(jìn)行網(wǎng)絡(luò)請(qǐng)求并返回 
   if (result != nil) {
      return result; 
   } else { 
      if (error != NULL) {//判斷調(diào)用方是否需要獲取錯(cuò)誤信息
         error = [NSError errorWithDomain:...]; //生成錯(cuò)誤對(duì)象 
      } 
      return nil; 
   }
}

上面的代碼會(huì)發(fā)生什么?如果在上面代碼的基礎(chǔ)上在外部創(chuàng)建一個(gè)錯(cuò)誤對(duì)象然后調(diào)用方法,最后打?。?/p>

NSError *error;
[self doSomethingWithObj:nil error:error];
NSLog(@"error: %@", error);

此時(shí)打印結(jié)果會(huì)是什么?運(yùn)行一下會(huì)發(fā)現(xiàn)控制臺(tái)輸出:

error: (null)

也就是說(shuō)方法中創(chuàng)建的新的NSError實(shí)例并沒(méi)有傳遞給外部的對(duì)象指針。其實(shí)分析一下可知道,error = [NSError errorWithDomain:...]; //生成錯(cuò)誤對(duì)象此處只是將新的實(shí)例指針?lè)峙浣o了error這個(gè)方法內(nèi)的局部指針變量,而這個(gè)局部指針變量是外部指針變量的一個(gè)拷貝。

當(dāng)方法調(diào)用結(jié)束,外部并沒(méi)有對(duì)這個(gè)新實(shí)例的強(qiáng)引用,因此也就會(huì)被釋放掉。同時(shí)外部的NSError指針也無(wú)法指向這個(gè)新的對(duì)象。

這就好比那個(gè)指針交換數(shù)值的例子,將其轉(zhuǎn)換成錯(cuò)誤的值傳遞:

void swap(int a, int b) {
   int tmp = a; a = b; b = tmp;
}

此處只是對(duì)局部變量a, b進(jìn)行了交換,函數(shù)出棧后,這兩個(gè)局部變量都被釋放,而外部的變量值并不改變。

回到NSError,為了能夠?qū)⒎椒ㄖ袆?chuàng)建的NSError實(shí)例分配給外部的那個(gè)error指針指向的地址,我們需要將外部指針變量存儲(chǔ)的地址直接傳遞給方法進(jìn)行值拷貝,而不是傳遞指針變量本身。這是因?yàn)槿绻麄鬟f指針變量本身的話,方法只會(huì)拷貝一個(gè)指針,雖然拷貝后的指針和外部的指針都指向同一個(gè)地址,但是指針本身的地址是不同的。

而如果傳遞&error,即取error指針本身的地址,則是單純的值拷貝(但實(shí)際情況略有區(qū)別,稍復(fù)雜一些,因?yàn)榇颂幵黾恿?code>__autorelease關(guān)鍵字,將指針對(duì)象自動(dòng)入池,這個(gè)過(guò)程會(huì)對(duì)指針地址做一些處理,導(dǎo)致拷貝的地址會(huì)有偏移),會(huì)保留這個(gè)指針的地址并在方法內(nèi)部恢復(fù)指針,同時(shí)新建NSError實(shí)例并取地址給這個(gè)指針。

類(lèi)似的,我們可以寫(xiě)一個(gè)交換NSError的方法來(lái)跟交換數(shù)值的方法進(jìn)行對(duì)比理解:

- (void)swapError:(NSError **)a with:(NSError **)b {
    NSError *tmp = *a;
    *a = *b;
    *b = tmp;
}

因此,我們可以得出一個(gè)結(jié)論,就是使用參數(shù)傳遞返回OC指針類(lèi)型的對(duì)象時(shí),指針的指針是一種比較方便的處理參數(shù)返回方式。

如有錯(cuò)誤望不吝指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 指針是C語(yǔ)言中廣泛使用的一種數(shù)據(jù)類(lèi)型。 運(yùn)用指針編程是C語(yǔ)言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); ...
    朱森閱讀 3,624評(píng)論 3 44
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛(ài)閱讀 2,255評(píng)論 0 7
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛(ài)DE問(wèn)候閱讀 1,846評(píng)論 0 4
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,698評(píng)論 1 51
  • 感恩!爸爸好早就做好午飯,等待我們回家。回家的感覺(jué)真好。謝謝!謝謝!謝謝! 感恩!女兒說(shuō)我是馬后炮,事后諸葛亮,我...
    梧桐70閱讀 220評(píng)論 0 0

友情鏈接更多精彩內(nèi)容