ObjC委托方法永远不会被调用
我正在创建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:无];
您的委托方法永远不会被调用,因为请求永远不会被创建。当您拨打callAPIMethodWithGET:
时,它会设置通信在当前线程的运行循环中异步运行,然后立即返回。这样你可以安全地在主线程上调用它而不会阻塞。
由于您是从您自己创建的线程调用该方法的,因此它不会看到主运行循环,而是新线程的运行循环。但是,由于您从不执行运行循环,所以不会发送消息,永远不会收到响应,并且您的委托也不会被调用。
您可能通过在您的新线程中调用[[NSRunLoop currentRunLoop] run]
来解决此问题。这将让工作发生。 但是在这种情况下,首先永远不会分离新线程。你的程序不会阻塞,你不必担心你的委托方法需要重入。
我不熟悉这些闪烁API包装,但在此代码:
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,@"api_key",self.ID,@"photo_id",nil];
你确定这两个FLICKR_API_KEY和self.ID不是零?如果他们中的任何一个都是零,那么最终会出现一个字典,其中的项目比您想要的要少。
乔恩 - 感谢,我很确定他们不是 - 虽然我仍然在Xcode中的变量观看挣扎,并最终在我的代码中放了很多NSLog()语句。我会仔细检查一下。 – mvexel 2009-12-09 11:16:23
刚刚做过,实际上它们不是零。 最后我得到的GDB输出是 [切换到进程87776] 编程接收信号:“EXC_BAD_ACCESS”。 [切换到进程87776] 这使我认为异步API请求的回调被发送到不存在的东西。 – mvexel 2009-12-09 11:20:30
我现在直接调用getLocation,现在调用回调。在这种情况下,线程并不是必需的,因为无论如何ObjectiveFlickr API都是异步的。现在遇到不同的麻烦,会在不同的线程中跟进,谢谢。 – mvexel 2009-12-10 14:57:55
OFFICElickrAPIRequest的setDelegate方法不保留委托,就像它应该。这意味着,只要请求是(或者修补类以正确拥有自己的引用),就可以确保代理处于活动状态。
这听起来像是可能是正确的回答,但是当你说“死亡没有像应该保留代表一样”时,这就不太合适。代表通常不被保留,这是有意的。例如,如果一个表视图保留它的委托,一个UITableViewController,那么会有一个保留周期,因为控制器也保留了表视图。代表几乎总是这些关系中的所有者,因此委托参考是非保留的。在Mac OS X上,这当然更容易实现垃圾回收。 – 2009-12-09 17:46:32
这很有道理,因为如果代理被保留,您可能会得到循环引用。 – 2009-12-10 02:39:25
请求,并在不同的线程解析XML我的解决方案时,我也遇到这个问题是这样做:
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){
}
哪里start = [NSDate dateWithTimeIntervalSinceNow:3];
这基本上是一个超时,这样它不会永远活着并且isFinished
在解析完成时设置为true。
这是一个有效的解决方案,但是如果请求和解析都是通过运行循环发生的,那么不需要首先将它放在单独的线程上。 – benzado 2009-12-11 20:39:37
你可以发布你已经实现的回调方法 - 这可能只是简单的错字,因为如果代理没有实现所需的回调,OFFlickrAPIRequest
将不会执行任何操作。
您是否还实施了flickrAPIRequest:didFailWithError:
以查看是否存在API调用返回的错误?
好的,我在上面的一些建议帮助下解决了它。
- 我确实删除了额外的
retain
,因为它确实造成了内存泄漏。它从一开始看起来并不正确,所以我对此的直觉是值得的,这是一件好事;) - 我删除了冗余线程,因为API调用已经是异步的,并且不需要额外的线程无阻塞。之后,回调方法被调用,但我遇到了与物体保留有关的不同问题。如果有兴趣,你可能想看看that question,
谢谢大家。
您应该删除for循环中额外的'retain'调用。该数组确实保留其成员,所以您基本上正在创建内存泄漏。 – benzado 2009-12-11 20:26:41