简体   繁体   English

从类别类方法实现中的内部块中返回对象

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM