Search code examples
iosobjective-cnsurlsessionnsoperationnsoperationqueue

Call NSURLSession method from inside the subclass of NSOperation


I my application I have table view with custom cell, that has:

@property (weak, nonatomic) IBOutlet UIImageView *image;
@property (weak, nonatomic) IBOutlet UILabel *nameOfImage;
@property (weak, nonatomic) IBOutlet UIButton *start;

I need to download any number of images asynchronously (by pressing a lot of start buttons). For this purpose I created subclass of NSOperation - MyOperationQueue. implementation of it looks like this:

- (id)initWithURL:(NSURL*)url andRaw:(NSInteger)row
{
    if (![super init])
        return nil;
    [self setTargetURL:url];
    [self setCurrentCell:row];
    self.customCell = [[CustomTableViewCell alloc]init];
    self.tableView = [ContentTableView sharedManager];
    return self;
}

- (void)main
{
    if ([self isCancelled])return;
    self.defaultSession = [self configureSession];
    NSURLSessionDownloadTask *task = [self.defaultSession downloadTaskWithURL:self.targetURL];
    if ([self isCancelled])  return;
    [task resume];
 }

- (void)cancel
{
    self.isCancelled = YES;
       if(self.downloadTask.state == NSURLSessionTaskStateRunning)
        [self.downloadTask cancel];
}

among this methods I have also described here NSURLSession methods:

    - (NSURLSession *) configureSession //it visits it
    {
 NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self.tableView **delegateQueue:self**];  //self - warning - incompatible pointer type sending "MyOperationQueue" to "NSOperationQueue" _Nullable.

}

-(void)URLSession:(NSURLSession *)session
         downloadTask:(NSURLSessionDownloadTask *)downloadTask
         didWriteData:(int64_t)bytesWritten
    totalBytesWritten:(int64_t)totalBytesWritten
    totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite // don't visit

-(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location    // don't visit

I create the custom queue in method in TableView:

   - (void)didClickStartAtIndex:(NSInteger)cellIndex withData:(CustomTableViewCell*)data
    {
        NSURL *url = [NSURL URLWithString: tmp.imeageURL];
        MyOperationQueue * one = [[MyOperationQueue alloc]initWithURL:url andRaw:self.selectedCell];
        [self.queue addOperation:one];
    }

The image is not loaded at all, the queue just enter into configuration method and thats all. Please advise me whats wrong? Thank you in advance.

EDIT: Updating UI:

-(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    NSLog(@"didFinishDownloadingToURL - Queue");
    NSData *d = [NSData dataWithContentsOfURL:location];
    UIImage *im = [UIImage imageWithData:d];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.customCell.image.image = im;
        self.customCell.realProgressStatus.text = @"Downloaded";
        [self.tableView.tableView reloadData];
    });
}

Solution

  • Your class is a subclass of NSOperation, not NSOperationQueue So you can't specify it to use self as the target queue for the NSURLSession object. Frankly, you'd just use nil for the operation queue parameter, as you don't care which on which queue the delegate methods run. Or you can create your own operation queue, if you want. But you cannot use self.

    But make sure to dispatch any UI updates back to the main queue.

    Also, you must make this an asynchronous NSOperation subclass or else the operation will terminated and be deallocated before your delegate methods ever get a chance to be called.

    As a minor observation, I'd suggest renaming this class to be MyOperation, to avoid confusion between operations and operation queues.