ObjC 委托方法永远不会被调用

发布于 2024-08-13 18:09:56 字数 1906 浏览 6 评论 0原文

我正在创建 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

风透绣罗衣 2024-08-20 18:09:56

您的委托方法永远不会被调用,因为永远不会发出请求。当您调用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.

ま昔日黯然 2024-08-20 18:09:56

当在不同的线程上请求和解析 XML 时,我也遇到了这个问题,我的解决方案是这样做:

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

}

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:

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

}

Where start = [NSDate dateWithTimeIntervalSinceNow:3]; this is basically a timeout so that it doesn't live forever and isFinished is set to true when my parsing has completed.

听风吹 2024-08-20 18:09:56

我不熟悉这些闪烁 API 包装器,但在这段代码中:

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

您确定 FLICKR_API_KEY 和 self.ID 都不为零吗?如果它们中的任何一个为零,您最终会得到一本字典,其中的项目比您预期的要少。

I'm not familiar with these flicker API wrappers, but in this code:

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

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.

岁月静好 2024-08-20 18:09:56

您能否发布您已实现的回调方法 - 这可能只是一个简单的拼写错误,因为如果委托未实现所需的回调,则 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?

遗忘曾经 2024-08-20 18:09:56

好的,在上面一些建议的帮助下,我确实解决了这个问题。

  • 我确实删除了额外的 retain 因为它实际上造成了内存泄漏。它从一开始看起来就不对劲,所以我的直觉觉得这是值得的,这是一件好事;)
  • 我删除了多余的线程,因为 API 调用已经是异步的,不需要额外的线程来实现非阻塞。之后,回调方法被调用,但我遇到了有关对象保留的不同问题。如果有兴趣,您可能想查看该问题 ,也

谢谢大家。

Okay, I did solve it, with help from some of the suggestions above.

  • I did remove the extra 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 ;)
  • I removed the redundant threading because the API call is already asynchronous and does not require an additional thread to be non-blocking. After that, the callback method was being called but I ran into different problems concerning object retention. If interested you might want to check out that question, too

Thanks all.

牛↙奶布丁 2024-08-20 18:09:56

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文