2014-01-29 19 views
5

我有一些代碼可以下載圖像並將其分配到一個塊中。該代碼目前正常工作,但我想重構它到一個單獨的方法,但重構後,我得到一個編譯錯誤。重構代碼之後「遺漏__block類型說明符」編譯錯誤,但在重構之前沒問題

這是編譯並與下載的圖像被成功地分配運行的原代碼:

- (void) someMethod 
{ 
    … 
    MyObject* object = [[MyObject alloc] init]; 
    [self.objects addObject: object]; 

    NSString* graphRequest = [NSString stringWithFormat:@"%@%@%@", @"https://graph.facebook.com/", 
           fbid, 
           @"/picture?type=square"]; 
    FBRequest *fbRequest = [FBRequest requestForGraphPath: graphRequest]; 
    [fbRequest startWithCompletionHandler: 
    ^(FBRequestConnection *connection, id result, NSError *theError) 
    { 
     NSDictionary<FBGraphObject> *dict = (NSDictionary<FBGraphObject> *) result; 
     if (dict) 
     { 
      NSString* urlAsString = [dict objectForKey:@"id"]; 
      if ([urlAsString length] > 0) 
      { 
       NSURL *url = [NSURL URLWithString: urlAsString]; 
       NSData *data = [NSData dataWithContentsOfURL:url]; 
       object.image = [UIImage imageWithData:data]; 
      } 
     } 
    }]; 
} 

如果我把它重構爲那麼下面我得到一個編譯錯誤

- (void) someMethod 
{ 
    … 
    MyObject* object = [[MyObject alloc] init]; 
    [self.objects addObject: object]; 
    [self fetchFbImage: object.image forFbid:fbid]; 
} 


- (void) fetchFbImage:(UIImage*) targetImage forFbid:(NSString*) fbid 
{ 
    NSString* graphRequest = [NSString stringWithFormat:@"%@%@%@", @"https://graph.facebook.com/", 
           fbid, 
           @"/picture?type=square"]; 
    FBRequest *fbRequest = [FBRequest requestForGraphPath: graphRequest]; 
    [fbRequest startWithCompletionHandler: 
    ^(FBRequestConnection *connection, id result, NSError *theError) 
    { 
     NSDictionary<FBGraphObject> *dict = (NSDictionary<FBGraphObject> *) result; 
     if (dict) 
     { 
      NSString* urlAsString = [dict objectForKey:@"id"]; 
      if ([urlAsString length] > 0) 
      { 
       NSURL *url = [NSURL URLWithString: urlAsString]; 
       NSData *data = [NSData dataWithContentsOfURL:url]; 
       targetImage = [UIImage imageWithData:data]; 
      } 
     } 
    }]; 
} 

編譯錯誤是分配給targetImage的行,「變量不可分配(缺少__block類型說明符)」。

我應該在哪裏添加__block類型說明符?爲什麼在重構之後有一個問題,但之前沒有?

感謝

在你的第一個方法

回答

4

您似乎對參數在Objective-C中的工作方式感到困惑。

在你原來的代碼,你有:

MyObject* object = [[MyObject alloc] init]; 

它聲明object作爲方法的局部變量。然後塊內你寫:

object.image = [UIImage imageWithData:data]; 

所以你的塊引用局部變量object(正如您對聲明沒有__block屬性)塊得到的變量的內容不斷副本。這很好,因爲你沒有改變object中的內容,它是對你的MyObject實例的引用,但是正在調用一個方法來改變該實例的內部狀態。[*]

現在讓我們來看看你的重構。您刪除了someMethod的代碼塊,並將其置於新方法fetchFbImage中。在someMethod你叫fetchFbImage

[self fetchFbImage:object.image forFbid:fbid]; 

此經過的object.image電流值的方法它通過財產以這樣一種方式,它可以在fetchFbImage被分配到。參數targetImage的參數類型爲UIImage * - 對UIImage的引用 - 它不是「UIImage *類型的屬性」 - 您不能擁有這種類型的參數,屬性不能只傳遞其值或引用具有屬性的對象。

當一個方法被稱爲每個參數實際上是其被初始化爲傳遞的參數值的局部變量,因此,上述方法調用有效地執行:

UIImage *targetImage = object.image; 

其中targetImage是在範圍的局部變量fetchFbImageobjectsomeMethod範圍內的局部變量。

現在的fetchFbImage內的塊中這樣寫:

  1. 不能塊內分配給targetImage

    targetImage = [UIImage imageWithData:data]; 
    

    這有兩個原因是錯誤的。這是一個局部變量,屬於fetchFbImage,局部變量不歸於__block,所以塊有一個不變的副本 - 你不能分配給常量。這就是編譯器發佈錯誤消息的原因。

  2. 但是你的問題比這個大,你假設一個fetchFbImage的局部變量targetImage的分配將會如何調用object.image這個屬性 - 而且它沒辦法做到這一點。 targetImage只是一個局部變量,通過方法調用用初始化爲object.image

解決這個問題的唯一辦法是通過fetchFbImage參考您MyObject實例,然後的fetchFbImage內塊內分配給該對象,就像您預先refectored代碼所做的image財產。

所以,你的代碼看起來是這樣的:

- (void) fetchFbImage:(MyObject *)targetObject forFbid:(NSString *)fbid 
{ 
    ... 
    targetObject.image = [UIImage imageWithData:data]; 
    ... 
} 

... 

[self fetchFbImage:object forFbid:fbid]; 

HTH

附錄

上看來你想fetchFbImage有沒有MyObject知識另外一個答案看到您的評論和無論將從何處引用圖像,都能夠獲取圖像。

一個簡單的方法是按照FBRequest的設計 - 使用完成處理程序。爲了方便起見定義類型爲完成塊:

typedef void (^ImageConsumer)(NSImage *image); 

現在定義的方法來利用這些之一:

- (void) fetchFbImageForFbid:(NSString *)fbid completionHandler:(ImageConsumer)handler 

在您的塊內fetchFbImageForFbid通過圖像處理程序:

handler([UIImage imageWithData:data]); 

而在通話中someMethod通過一個塊,它將值分配給您的財產:

[self fetchFbImageForFbid:fbid 
     completionHandler:^(NSImage *image) { object.image = image; } 
]; 

[*]如果這是參考一所房子的地址混亂的想法。地址是不變的,房子裏有多少人不是。你可以告訴某人「去這個地址,有一個偉大的派對」 - 房子的內容(「國家」)發生變化,地址不變。

+0

謝謝您的全面解答 – Gruntcakes

1

(帶出來重構),你可以設置圖像對象監守你有參照對象,所以你沒有

object.image = [UIImage imageWithData:data]; 

但是重構後,可以不像你所做的那樣設置圖像,你也應該發送對象。

- (void) someMethod 
{ 
    … 
    MyObject* object = [[MyObject alloc] init]; 
    [self.objects addObject: object]; 
    [self fetchFbImageForObj:object forFbid:fbid]; 
} 


- (void) fetchFbImageForObject:(MyObject*)object forFbid:(NSString*) fbid 
{ 
    NSString* graphRequest = [NSString stringWithFormat:@"%@%@%@", @"https://graph.facebook.com/", 
           fbid, 
           @"/picture?type=square"]; 
    FBRequest *fbRequest = [FBRequest requestForGraphPath: graphRequest]; 
    [fbRequest startWithCompletionHandler: 
    ^(FBRequestConnection *connection, id result, NSError *theError) 
    { 
     NSDictionary<FBGraphObject> *dict = (NSDictionary<FBGraphObject> *) result; 
     if (dict) 
     { 
      NSString* urlAsString = [dict objectForKey:@"id"]; 
      if ([urlAsString length] > 0) 
      { 
       NSURL *url = [NSURL URLWithString: urlAsString]; 
       NSData *data = [NSData dataWithContentsOfURL:url]; 
       object.image = [UIImage imageWithData:data]; 
      } 
     } 
    }]; 
} 

試試吧。如果有任何錯誤或者其他,請在下面留言。

+0

謝謝,那是什麼解釋?爲什麼圖像不能以這種方式設置? – Gruntcakes

+0

是的,它編譯,謝謝。你能解釋爲什麼請。 – Gruntcakes

+0

圖像無法設置,因爲將新下載的圖像分配給目標圖像不會導致將該targetImage分配給對象。 Object.image是指向某個UIImage對象的指針。 – santhu

相關問題