2009-12-08 61 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

谢谢大家。

相关问题