Completion block/callback on FetchRequest completi

2019-08-18 17:24发布

问题:

I have a FetchRequest in my model class named ContentManager. It fetches quite a lot of data, so the screen is blank until it's completion. In the ViewController that displays the fetched results, I would like to show a loading indicator, so I would like to get a callback when the FetchRequest has completed and pass that to the ViewController to stop the loading indicator. Is this possible?

Here is the FetchRequest from the ContentManager class:

- (NSArray*)recipesForMagazine
{
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Recipe" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];

    NSString* path = [[NSBundle mainBundle] pathForResource:@"magazine_recipe_guids" ofType:@"plist"];
    NSArray* recipeGuids = [NSArray arrayWithContentsOfFile:path];

    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"guid IN %@",recipeGuids];
    [request setPredicate:predicate];

    NSSortDescriptor* sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
    [request setSortDescriptors:[NSArray arrayWithObject:sort]];

    [sort release];

    NSError* error = nil;
    NSArray* fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
    [request release];

    return fetchResults;        
}

Here I set it up in the ViewController

self.magazineRecipes = [[ContentManager defaultManager] recipesForMagazine];

I want to set up the fetchrequest method like this:

- (NSArray*)recipesForMagazine:(void (^)(BOOL success))block or something, so in the viewcontroller I can call it like this

self.magazineRecipes = [[CTContentManager defaultManager] recipesForMagazine:^(BOOL success) {
    if (success) {
        //stop activity indicator view
    }
}];

I don't know if I'm at all in the right way of thinking, thanks for your help in advance!

回答1:

I would make the viewController a delegate of the ContentManager class. So in the ContentManager.h I would do something like:

    @protocol ContentManagerDelegate()
      -(void) didFetchResults:(NSArray *) results;
      -(void) didResultsFail: (NSError *) error;
    @end

    @interface ContentManager : <SuperClass Name>
    -(id) initWithDelegate: (id<ContentManagerDelegate>) delegate;
    @property (nonatomic, strong) id<ContentManagerDelegate> delegate;
    @end

and in the implementation:

   -(id) initWithDelegate: (id<ContentManagerDelegate>) delegate
    {
        self = [super init];
        if(self)
        {
           _delegate = delegate;
         }
        return self;
    }

and in your recipesForMagazine method you can use the delegate [_delegate didFetchResults: fetchResults], you can implement a method to pass errors to the delegate if you want as well. In your ViewController.h do @interface ViewController.h : UIViewController <ContentManagerDelegate> and in the implementation you should be able to implement the didFetchResults: method that will give you the results and in that method you can stop the activity indicator from animating.