2011-05-23 12 views
1

以下代碼用於下載圖像並返回塊的結果,以便利用塊和Grand Central Dispatch的異步功能。我發現如果圖像或錯誤對象是零,我會得到一個EXC_BAD_ACCESS錯誤。如果參數的值爲零,是否會導致錯誤?Objective-C中的塊是否可以將一個零值作爲參數?

失敗的部分是returnImage塊,用於在方法結束時返回圖像。

- (void)downloadImageWithBlock:(void (^)(UIImage *image, NSError *error))returnImage { 
    dispatch_queue_t callerQueue = dispatch_get_current_queue(); 
    dispatch_queue_t downloadQueue = dispatch_queue_create("Image Downloader Queue", NULL); 
    dispatch_async(downloadQueue, ^{ 
     UIImage *image = nil; 
     NSError *error; 

     // get the UIImage using imageURL (ivar) 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      NSLog(@"Downloading: %@", imageURL); 
     }); 

     NSURL *url = [NSURL URLWithString:imageURL]; 
     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 

     NSURLResponse *urlResponse = nil; 
     NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error]; 

     if (!error && response) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       NSLog(@"Success!"); 
      }); 
      image = [UIImage imageWithData:response]; 
     } 

     // image will be nil if the request failed 

     dispatch_async(callerQueue, ^{ 
      returnImage(image, error); 
     }); 
    }); 
    dispatch_release(downloadQueue); 
} 

下面是我不知道如何閱讀的堆棧跟蹤。

0x00002d20 <+0000> push %ebp 
0x00002d21 <+0001> mov %esp,%ebp 
0x00002d23 <+0003> sub $0x18,%esp 
0x00002d26 <+0006> mov 0x8(%ebp),%eax 
0x00002d29 <+0009> mov %eax,-0x4(%ebp) 
0x00002d2c <+0012> mov -0x4(%ebp),%eax 
0x00002d2f <+0015> mov 0x14(%eax),%eax 
0x00002d32 <+0018> mov %eax,(%esp) 
0x00002d35 <+0021> movl $0x3,0x4(%esp) 
0x00002d3d <+0029> call 0x314c <dyld_stub__Block_object_dispose> 
0x00002d42 <+0034> mov -0x4(%ebp),%eax 
0x00002d45 <+0037> mov 0x18(%eax),%eax 
0x00002d48 <+0040> mov %eax,(%esp) 
0x00002d4b <+0043> movl $0x3,0x4(%esp) 
0x00002d53 <+0051> call 0x314c <dyld_stub__Block_object_dispose> 
0x00002d58 <+0056> mov -0x4(%ebp),%eax 
0x00002d5b <+0059> mov 0x1c(%eax),%eax 
0x00002d5e <+0062> mov %eax,(%esp) 
0x00002d61 <+0065> movl $0x7,0x4(%esp) 
0x00002d69 <+0073> call 0x314c <dyld_stub__Block_object_dispose> 
0x00002d6e <+0078> add $0x18,%esp 
0x00002d71 <+0081> pop %ebp 
0x00002d72 <+0082> ret  
0x00002d73 <+0083> nopw 0x0(%eax,%eax,1) 
0x00002d79 <+0089> nopl 0x0(%eax) 
+0

什麼是使這個代碼難以調試的事實是,錯誤不會顯示在一行代碼中,所以我必須註釋掉大塊代碼以嘗試識別錯誤發生的位置。指出錯誤的代碼行很困難。 – Brennan 2011-05-23 23:58:35

回答

5

NSError *error;創建指向隨機/無效內存位置的指針。

如果塊中沒有發生錯誤,它將不會爲error分配新的(有效)值。其結果是,當你測試error是否是零,你訪問一個空指針:

NSError *error; // invalid pointer 
NSLog(@"%@", error); // crash -- dereferencing invalid pointer 

您應該:

  1. 始終分配零它們傳遞給這個方法之前出錯變量性質。
  2. 請查閱方法的文檔,它通常會告訴您錯誤變量是否有一個基於方法返回值分配給它的有效值。

更新:ARC下的本地對象變量現在默認爲nil。

+2

+1,我只是想強調一點:蘋果[保證](http:// developer。apple.com/library/ios/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html#//apple_ref/doc/uid/TP40001806-CH204-SW1)間接返回NSError對象的Cocoa方法將擁有一個有效的錯誤對象如果該方法用其返回值指示失敗。但是,它們不能保證相反:如果方法指示成功,則錯誤對象將爲零。除非方法的直接返回值指示失敗,否則檢查錯誤是不正確的。 – 2011-05-24 02:09:22

+0

謝謝賈森和喬希。這現在有道理。我在想這是一個GCD問題,因爲它只是一個局部變量問題。我還將一個ivar的imageURL的值設置爲局部變量,以便它不會成爲塊中的問題。現在代碼工作非常可靠。我確實發現我需要檢查HTTP狀態代碼,因爲沒有錯誤並不意味着我沒有得到403或404等。我現在需要200成功。 – Brennan 2011-05-24 02:33:38

+2

@Brennan總結:總是先檢查返回值。如果返回值指示錯誤(例如,它是'nil'或'NO'),請檢查'NSError'輸出參數。爲'NSError'變量賦值'nil'並依賴它是不健壯的。 – 2011-05-24 03:42:05

1

那麼幾個點,可以幫助的:

你不應該檢查錯誤或做任何假設有關錯誤,除非響應是零。

如果響應不是零,那麼錯誤是未定義的,但您要求塊保留錯誤。你確定這不是你的問題嗎?

你確定returnImage()可以處理nils(或未定義的NSError *)嗎?

+0

一般來說,不要將NSError指針設置爲零,儘管運行時會自動爲我們執行此操作。 @Brennan發佈堆棧跟蹤並檢查callerQueue。 – TheBlack 2011-05-24 00:12:24

+0

我已將堆棧跟蹤添加到問題中。 – Brennan 2011-05-24 00:35:26

+0

現在聲明時將錯誤設置爲零允許它在沒有異常的情況下運行。我不確定這裏發生了什麼事。 – Brennan 2011-05-24 00:37:33

相關問題