ObjC 委托方法永远不会被调用
我正在创建 FlickrImage 类的实例来解析 Flickr API 照片响应。该类有一个方法 getLocation,它执行另一个 API 调用来获取地理位置:
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:self withObject:nil];
I am creating instances of a class FlickrImage parsing a Flickr API photos response. The class has a method getLocation that does another API call to get the geolocation:
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];
I have implemented the callback method that would catch the response from the API and update the FlickrImage instance with the geolocation data - but it never gets called. Here's where the instances get created:
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];
}
The retain
is there because I thought it might help solve this but it doesn't - and doesn't the NSMutableArray (flickrImages is a NSMutableArray) retain its members anyway?
EDIT I should add that the getLocation
method (first code snippet) is launched in a thread:
[NSThread detachNewThreadSelector:@selector(getLocation) toTarget:self withObject:nil];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您的委托方法永远不会被调用,因为永远不会发出请求。当您调用
callAPIMethodWithGET:
时,它会设置通信以在当前线程的运行循环上异步运行,然后立即返回。这样你就可以在主线程上安全地调用它而不会阻塞。因为您是从自己创建的线程调用该方法,所以它看不到主运行循环,而是看到新线程的运行循环。但是,由于您从未执行运行循环,因此永远不会发送消息,永远不会收到响应,并且永远不会调用您的委托。
您可以通过在新线程中调用
[[NSRunLoop currentRunLoop] run]
来修复此问题。这会让工作发生。 但在这种情况下,从一开始就不分离新线程会更容易。您的程序不会阻塞,并且您不必担心委托方法需要可重入。Your delegate method is never being called because the request is never being made. When you call
callAPIMethodWithGET:
, it sets up communications to run asynchronously on the current thread's run loop, then returns immediately. That way you can safely call it on the main thread without blocking.Because you are calling the method from a thread you created yourself, it does not see the main run loop, but the run loop for your new thread. However, because you never execute the run loop, the messages are never sent, a response is never received, and your delegate is never called.
You could fix this by calling
[[NSRunLoop currentRunLoop] run]
in your new thread. That will let the work happen. But in this case would be easier to never detach a new thread in the first place. Your program won't block, and you won't have to worry about your delegate method needing to be reentrant.当在不同的线程上请求和解析 XML 时,我也遇到了这个问题,我的解决方案是这样做:
Where
start = [NSDate dateWithTimeIntervalSinceNow:3];
这基本上是一个超时,因此它不会当我的解析完成时,它不会永远存在,并且isFinished
设置为 true。I've also run into this problem when requesting and parsing XML on a different thread my solution was to do this:
Where
start = [NSDate dateWithTimeIntervalSinceNow:3];
this is basically a timeout so that it doesn't live forever andisFinished
is set to true when my parsing has completed.我不熟悉这些闪烁 API 包装器,但在这段代码中:
您确定 FLICKR_API_KEY 和 self.ID 都不为零吗?如果它们中的任何一个为零,您最终会得到一本字典,其中的项目比您预期的要少。
I'm not familiar with these flicker API wrappers, but in this code:
Are you certain that both FLICKR_API_KEY, and self.ID are not nil? If either of them is nil, you'll end up with a dictionary that has less items in it than you intend.
您能否发布您已实现的回调方法 - 这可能只是一个简单的拼写错误,因为如果委托未实现所需的回调,则
OFFlickrAPIRequest
将不会执行任何操作。您是否还实现了
flickrAPIRequest:didFailWithError:
以查看 API 调用是否返回错误?Could you post the callback method(s) you have implemented – this could be just down to a simple typo, as it appears
OFFlickrAPIRequest
won’t do anything if the delegate does not implement the required callback.Did you also implement
flickrAPIRequest:didFailWithError:
to see if there was an error returned from the API call?好的,在上面一些建议的帮助下,我确实解决了这个问题。
retain
因为它实际上造成了内存泄漏。它从一开始看起来就不对劲,所以我的直觉觉得这是值得的,这是一件好事;)谢谢大家。
Okay, I did solve it, with help from some of the suggestions above.
retain
because it did in fact create a memory leak. It did not look right from the outset, so my gut feeling about that is worth something, which is a good thing ;)Thanks all.
OFFlickrAPIRequest 的 setDelegate 方法不保留委托就像它应该的那样。这意味着您必须确保只要请求存在,您的委托就处于活动状态(或者修补该类以正确拥有其自己的引用)。
The setDelegate method of OFFlickrAPIRequest does not retain the delegate like it should. This means you're stuck ensuring that your delegate is alive as long as the request is (or patching the class to properly own its own references).