2009-12-08 85 views
2

我正在創建FlickrImage類的實例,解析Flickr API照片響應。這個類有,做另一個API調用來獲取地理定位的方法的getLocation:ObjC委託方法永遠不會被調用

NSLog(@"getting location for %i",self.ID); 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
OFFlickrAPIRequest *flickrAPIRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext[appDelegate sharedDelegate].flickrAPIContext]; 
[flickrAPIRequest setDelegate:self]; 

NSString *flickrAPIMethodToCall = @"flickr.photos.geo.getLocation"; 
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,@"api_key",self.ID,@"photo_id",nil]; 

[flickrAPIRequest callAPIMethodWithGET:flickrAPIMethodToCall arguments:requestArguments]; 
[pool release]; 

我已經實現,將趕上來自API的響應,並與地理定位數據更新FlickrImage實例的回調方法 - 但它從來沒有被調用。下面是其中的情況下獲得創建:

NSDictionary *photosDictionary = [inResponseDictionary valueForKeyPath:@"photos.photo"]; 
NSDictionary *photoDictionary; 
FlickrImage *flickrImage; 
for (photoDictionary in photosDictionary) { 
    flickrImage = [[FlickrImage alloc] init]; 
    flickrImage.thumbnailURL = [[appDelegate sharedDelegate].flickrAPIContext photoSourceURLFromDictionary:photoDictionary size:OFFlickrThumbnailSize]; 
    flickrImage.hasLocation = TRUE; // TODO this is actually to be determined... 
    flickrImage.ID = [NSString stringWithFormat:@"%@",[photoDictionary valueForKeyPath:@"id"]]; 
    flickrImage.owner = [photoDictionary valueForKeyPath:@"owner"]; 
    flickrImage.title = [photoDictionary valueForKeyPath:@"title"]; 
    [self.flickrImages addObject:[flickrImage retain]]; 
    [flickrImage release]; 
    [photoDictionary release]; 
} 

retain是那裏,因爲我認爲這可能有助於解決這一點,但它沒有 - 也確實不是NSMutableArray裏(flickrImages是NSMutableArray的)反正保留其成員?

編輯我應該補充的是,getLocation方法(第一代碼段)在一個線程被推出: [NSThread detachNewThreadSelector:@selector(的getLocation)toTarget:自withObject:無];

+0

您應該刪除for循環中額外的'retain'調用。該數組確實保留其成員,所以您基本上正在創建內存泄漏。 – benzado 2009-12-11 20:26:41

回答

2

您的委託方法永遠不會被調用,因爲請求永遠不會被創建。當您撥打callAPIMethodWithGET:時,它會設置通信在當前線程的運行循環中異步運行,然後立即返回。這樣你可以安全地在主線程上調用它而不會阻塞。

由於您是從您自己創建的線程調用該方法的,因此它不會看到主運行循環,而是新線程的運行循環。但是,由於您從不執行運行循環,所以不會發送消息,永遠不會收到響應,並且您的委託也不會被調用。

可能通過在您的新線程中調用[[NSRunLoop currentRunLoop] run]來解決此問題。這將讓工作發生。 但是在這種情況下,首先永遠不會分離新線程。你的程序不會阻塞,你不必擔心你的委託方法需要重入。

0

我不熟悉這些閃爍API包裝,但在此代碼:

NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,@"api_key",self.ID,@"photo_id",nil]; 

你確定這兩個FLICKR_API_KEY和self.ID不是零?如果他們中的任何一個都是零,那麼最終會出現一個字典,其中的項目比您想要的要少。

+0

喬恩 - 感謝,我很確定他們不是 - 雖然我仍然在Xcode中的變量觀看掙扎,並最終在我的代碼中放了很多NSLog()語句。我會仔細檢查一下。 – mvexel 2009-12-09 11:16:23

+0

剛剛做過,實際上它們不是零。 最後我得到的GDB輸出是 [切換到進程87776] 編程接收信號:「EXC_BAD_ACCESS」。 [切換到進程87776] 這使我認爲異步API請求的回調被髮送到不存在的東西。 – mvexel 2009-12-09 11:20:30

+1

我現在直接調用getLocation,現在調用回調。在這種情況下,線程並不是必需的,因爲無論如何ObjectiveFlickr API都是異步的。現在遇到不同的麻煩,會在不同的線程中跟進,謝謝。 – mvexel 2009-12-10 14:57:55

-1

OFFICElickrAPIRequest的setDelegate方法不保留委託,就像它應該。這意味着,只要請求是(或者修補類以正確擁有自己的引用),就可以確保代理處於活動狀態。

+2

這聽起來像是可能是正確的回答,但是當你說「死亡沒有像應該保留代表一樣」時,這就不太合適。代表通常不被保留,這是有意的。例如,如果一個表視圖保留它的委託,一個UITableViewController,那麼會有一個保留週期,因爲控制器也保留了表視圖。代表幾乎總是這些關係中的所有者,因此委託參考是非保留的。在Mac OS X上,這當然更容易實現垃圾回收。 – 2009-12-09 17:46:32

+0

這很有道理,因爲如果代理被保留,您可能會得到循環引用。 – 2009-12-10 02:39:25

1

請求,並在不同的線程解析XML我的解決方案時,我也遇到這個問題是這樣做:

while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){ 

} 

哪裏start = [NSDate dateWithTimeIntervalSinceNow:3];這基本上是一個超時,這樣它不會永遠活着並且isFinished在解析完成時設置爲true。

+0

這是一個有效的解決方案,但是如果請求和解析都是通過運行循環發生的,那麼不需要首先將它放在單獨的線程上。 – benzado 2009-12-11 20:39:37

0

你可以發佈你已經實現的回調方法 - 這可能只是簡單的錯字,因爲如果代理沒有實現所需的回調,OFFlickrAPIRequest將不會執行任何操作。

您是否還實施了flickrAPIRequest:didFailWithError:以查看是否存在API調用返回的錯誤?

0

好的,我在上面的一些建議幫助下解決了它。

  • 我確實刪除了額外的retain,因爲它確實造成了內存泄漏。它從一開始看起來並不正確,所以我對此的直覺是值得的,這是一件好事;)
  • 我刪除了冗餘線程,因爲API調用已經是異步的,並且不需要額外的線程無阻塞。之後,回調方法被調用,但我遇到了與物體保留有關的不同問題。如果有興趣,你可能想看看that question

謝謝大家。

相關問題