Question

I'm creating a lot of NSOperations (subclasses) that sort through a bunch of data. When they're done, I'd like them "return" that data and put it into a mutable array or something. Order doesn't matter.

Is something like this is possible?

Was it helpful?

Solution 2

Sure. Declare a delegate in NSOperation subclass. Then after finish of operation

if([self.delegate respondsToSelector:@selector(YourDelegate:)]) {
    [(NSObject *)self.delegate performSelectorOnMainThread:@selector(YourDelegate:) withObject:self waitUntilDone:NO];
}

In UI

-(void)YourOperationDidFinish:(YourOperation *)downloader {
    if(downloader.downloadItem) {
        // processing with your object       
    }
}

OTHER TIPS

An alternative to the protocol-delegate pattern is a completion block. For example, in some random NSURLConnection based operation, I define a completion block typedef (just to simplify the block syntax later) that returns a NSData if successful, or an NSError if not:

typedef void(^CustomOperationCompletionBlock)(NSData *data, NSError *error);

I can then define a block property for my NSOperation subclass, e.g.:

@property (nonatomic, copy) CustomOperationCompletionBlock successFailureBlock;

I'll often have a rendition of my init method of my operation that will let me set that completion block during the init process (in addition to anything else I want to initialize):

- (instancetype)initWithURL:(NSURL *)url successFailureBlock:(CustomOperationCompletionBlock)successFailureBlock;

My various methods that handle errors and/or success within my operation would then call that completion block to pass the data back:

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    if (self.successFailureBlock) {
        // whether you call the completion block on the main queue, or use whatever queue the operation is using, is up to you. Here I'll call the completion block on the main queue:

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.successFailureBlock(nil, error);
        }];
    }

    [self completeOperation];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if (self.successFailureBlock) {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.successFailureBlock(self.data, nil);
        }];
    }

    [self completeOperation];
}

And, to use this operation with custom completion block handler, when I initiate my operation, I can just pass it a custom completion block. For example, this saves the data if successful, or logs the error if not:

CustomOperation *operation = [[CustomOperation alloc] initWithURL:url successFailureBlock:^(NSData *data, NSError *error) {
    if (error)
        NSLog(@"CustomOperation error: %@", error);
    else         
        [data writeToFile:path atomically:YES];
}];

[queue addOperation:operation];

Clearly, you would change the block typedef to pass back whatever objects that make sense for your operation. But this illustrates the basic pattern of a block-based mechanism for a NSOperation subclass to return data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top