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

时间:2014-10-02 14:53:31

标签: objective-c objective-c-blocks objective-c-category

我的实施遇到了一些问题,我真的不知道如何解决。请你指教。

我尝试使用一个类方法实现NSManagedObject类别类Photo + Flickr.m +(void)photoWithFlickrData:inManagedObjectContext:

我想要做的是使用NSURLSessionDownloadTask从Flickr API下载数据,然后创建Photo对象并将这个新创建的对象插入数据库(如果它还没有存在)。这部分工作正常。

最后我想返回新创建的(或在db中找到的对象)Photo对象。这就是我遇到问题的地方。由于我使用类别I,因此无法使用实例变量。我无法找到任何好的解决方案来从此completionHandler块中获取此Photo对象。

我的代码:

@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;
}

我真的很感激有关如何实现这一点的任何建议。

2 个答案:

答案 0 :(得分:2)

由于您在块中发生了异步操作,因此您需要将完成处理程序(块)传递给photoWithFlickrData:inManagedObjectContext:方法,并在拥有有效的照片数据时调用它。

您需要在方法中添加一个新参数,以便传入完成处理程序。我会做这样的事情:

+ (void)photoWithFlickrData:(NSDictionary *)photoDictionary
     inManagedObjectContext:(NSManagedObjectContext *)context
      withCompletionHandler:(void(^)(Photo *photo))completionHandler

然后,当您拥有有效的photo个对象时,请像这样致电completionHandler

completionHandler(photo);

看起来你想把它放在你传递给dispatch_async的街区的最后:

/* ... */
dispatch_async(dispatch_get_main_queue(), ^{
    Photo *photo = nil;

    /* ... */

    completionHandler(photo);
});
/* ... */

然后,您可以这样调用您的方法:

[Photo photoWithFlickrData:photoDictionary
    inManagedObjectContext:context
     withCompletionHandler:^(Photo* photo) {
         /* use your valid photo object here */
     }
];

答案 1 :(得分:-1)

在致电[session downloadTaskWithRequest:.....]之前,在您的街区之外定义一个像这样的变量

__block Photo *photoObject = nil;

然后在完成设置其属性后在块内,设置

photoObject = photo;

现在,您可以使用块外的photoObject变量执行任何操作。 查看this Apple developer documentation on Blocks and Variables