[英]Returning an object from inside block within category class method implementation
I have run into a certain problem with my implementation which I don't really know how to solve. 我的实现遇到了一个我实际上不知道如何解决的问题。 Could You please advise. 您能否提一些建议。
I'm trying to implement an NSManagedObject category class Photo+Flickr.m with one class method +(void)photoWithFlickrData:inManagedObjectContext: 我正在尝试使用一种类方法+(void)photoWithFlickrData:inManagedObjectContext实现NSManagedObject类别类Photo + Flickr.m:
What I would like to do is download data from Flickr API using NSURLSessionDownloadTask and then create Photo object and insert this new created object into database (if it's not already there). 我想做的是使用NSURLSessionDownloadTask从Flickr API下载数据,然后创建Photo对象,并将这个新创建的对象插入数据库(如果尚不存在)。 This part works fine. 这部分工作正常。
And at the end I would like to return new created (or object that was found in db) Photo object. 最后,我想返回新创建的(或在db中找到的对象)Photo对象。 And this is where I run into problem. 这就是我遇到的问题。 Since I'm using category I can't use instance variables. 由于我使用类别,因此无法使用实例变量。 I can't really find any good solution to get this Photo object from inside this completionHandler block. 我真的找不到任何好的解决方案来从此completeHandler块内部获取此Photo对象。
My code: 我的代码:
@implementation Photo (Flickr)
+ (void)photoWithFlickrData:(NSDictionary *)photoDictionary
inManagedObjectContext:(NSManagedObjectContext *)context
{
NSString *placeId = [photoDictionary valueForKeyPath:FLICKR_PHOTO_PLACE_ID];
NSURL *urlInfoAboutPlace = [FlickrFetcher URLforInformationAboutPlace:placeId];
NSURLRequest *request = [NSURLRequest requestWithURL:urlInfoAboutPlace];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDownloadTask *task =
[session downloadTaskWithRequest:request
completionHandler:^(NSURL *localfile, NSURLResponse *response, NSError *error) {
if(!error) {
NSData *json = [NSData dataWithContentsOfURL:localfile];
NSDictionary *flickrPlaceDictionary = [NSJSONSerialization JSONObjectWithData:json
options:0
error:NULL];
dispatch_async(dispatch_get_main_queue(), ^{
Photo *photo = nil;
// flickr photo unique id
NSString *uniqueId = [photoDictionary valueForKeyPath:FLICKR_PHOTO_ID];
NSFetchRequest *dbRequest = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
dbRequest.predicate = [NSPredicate predicateWithFormat:@"uniqueId = %@", uniqueId];
NSError *error;
NSArray *reqResults = [context executeFetchRequest:dbRequest error:&error];
if (!reqResults || error || [reqResults count] > 1) {
//handle error
} else if ([reqResults count]) {
//object found in db
NSLog(@"object found!");
photo = [reqResults firstObject];
} else {
//no object in db so create a new one
NSLog(@"object not found, creating new one");
photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo"
inManagedObjectContext:context];
//set its properties
photo.uniqueId = uniqueId;
photo.title = [photoDictionary valueForKey:FLICKR_PHOTO_TITLE];
photo.region = [FlickrFetcher extractRegionNameFromPlaceInformation:flickrPlaceDictionary];
NSLog(@"title: %@", photo.title);
NSLog(@"ID: %@", photo.uniqueId);
NSLog(@"region: %@", photo.region);
}
});
}
}];
[task resume];
//how to get Photo *photo object???
//return photo;
}
I would really appreciate any suggestions on how to implement this. 我非常感谢有关如何实现此建议的任何建议。
Since you have async operations happening inside your blocks, you'll need to pass a completion handler (block) to your photoWithFlickrData:inManagedObjectContext:
method and call it when you have valid photo data. 由于您的块中发生了异步操作,因此需要将完成处理程序(块)传递给photoWithFlickrData:inManagedObjectContext:
方法,并在拥有有效照片数据时调用它。
You'll need to add a new parameter to your method so you can pass in the completion handler. 您需要向您的方法添加一个新参数,以便您可以传入完成处理程序。 I'd do something like this: 我会做这样的事情:
+ (void)photoWithFlickrData:(NSDictionary *)photoDictionary
inManagedObjectContext:(NSManagedObjectContext *)context
withCompletionHandler:(void(^)(Photo *photo))completionHandler
Then, when you have a valid photo
object, call completionHandler
like so: 然后,当您有一个有效的photo
对象时,如下所示调用completionHandler
:
completionHandler(photo);
It looks like you'd want to put that at the very end of the block you're passing to dispatch_async
: 您似乎希望将其放在要传递给dispatch_async
的块的末尾:
/* ... */
dispatch_async(dispatch_get_main_queue(), ^{
Photo *photo = nil;
/* ... */
completionHandler(photo);
});
/* ... */
Then, you can call your method like so: 然后,您可以像这样调用您的方法:
[Photo photoWithFlickrData:photoDictionary
inManagedObjectContext:context
withCompletionHandler:^(Photo* photo) {
/* use your valid photo object here */
}
];
Outside of your block before you call [session downloadTaskWithRequest:.....]
define a variable like this 在调用[session downloadTaskWithRequest:.....]
之前,请在代码块之外定义一个这样的变量
__block Photo *photoObject = nil;
Then inside the block after you finish setting its properties, set 完成设置其属性后,在块内进行设置
photoObject = photo;
Now you can do whatever you want with the photoObject
variable outside of the block. 现在,您可以使用块外部的photoObject
变量执行任何操作。 Check out this Apple developer documentation on Blocks and Variables . 查看有关块和变量的Apple开发人员文档 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.