0

i have written code to downloading data from server using NSOperationQueue and NSOperation. and now i want to show progress on UserInterface. i used UITableView and used NSOpeartionQueue as a datasource in tableview delegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
   return [[[Downloadmanager sharedInstance] downloadOperationQueue] count];    
}

and bind NSOperation`s properties to UITableViewCell.

  • 1) Is this a fisible solution to sending NSOperationQueue as a datasource to tableview delegate ?
  • 2) How to implement notification to reload tableview when NSOperation's state changes?

Thanks.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
iOS_Developer
  • 495
  • 4
  • 20
  • Any update on your question? Did you find any solution helpful? – Michal Apr 15 '14 at 11:36
  • Hi, Thanks. No. i didn't find any solution actually, the situation is - i create one operation say PDOperation that runs on PDOperationQueue and inside this i put one NSOperationQueue and add operations say PDChunkOperation to this queue. The PDOperation is for calculating data (fetch from database), copy file from Asset to documentary directory, and than encrypt file, PDChunkOperation is used to upload file in chunk as PDChunkOperation. and now the problem is deallocation of operations. – iOS_Developer Apr 15 '14 at 13:10
  • and the requirement is to setMaxConcurrentOperationCount say 2 to both queue. and i track progress of chunk operation into PDChunkOperationQueue (subclass of NSOperationQueue). – iOS_Developer Apr 15 '14 at 13:15
  • Whoa who, so you're putting a queue inside a queue? Isn't that a bit of overkill? There must be a way to flatten that hierarchy - make it one queue... – Michal Apr 15 '14 at 15:18
  • i m putting a queue inside a NSoperation !!. now is it fine ? and my deallocation issue is solved .... – iOS_Developer Apr 16 '14 at 04:50
  • Well you said that you have PDOperationQueue to which you put NSOperationQueues, which sounded like you have a two dimensional queue :) so deallocation is fine the only thing is the progress tracking right? – Michal Apr 16 '14 at 04:56
  • sorry for that mistake. yes, and now i am searching best way to get progress and bind to Userinterface. Thanks – iOS_Developer Apr 16 '14 at 05:30

2 Answers2

0
  1. I don't think it's the proper way of showing progress using NSOperationQueue as a datasource to tableview. You can use networking library like AFNetworking for downloading data and use setDownloadProgressBlock: method for showing progress. Refer this link for the code download progress.

  2. It's easy to reload tableview when the download completes, just call [tableView reloadData] in completionblock.

Here is the code which shows image downloading using AFNetworking which you can easily change for data download.(refer this gist)

 - (void)downloadMultiAFN {
    // Basic Activity Indicator to indicate download
    UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    [loading startAnimating];
    [self.imageView.superview addSubview:loading];
    loading.center = self.imageView.center;

    // Create a request from the url, make an AFImageRequestOperation initialized with that request
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.picUrl]];
    AFImageRequestOperation *op = [[AFImageRequestOperation alloc] initWithRequest:request];

    // Set a download progress block for the operation
    [op setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        if ([op.request.URL.absoluteString isEqualToString:@"http://www.pleiade.org/images/hubble-m45_large.jpg"]) {
            self.progressBar.progress = (float) totalBytesRead/totalBytesExpectedToRead;
        } else self.progressBar2.progress = (float) totalBytesRead/totalBytesExpectedToRead;
    }];

    // Set a completion block for the operation
    [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        self.imageView.image = responseObject;
        self.image = responseObject;
        if ([op.request.URL.absoluteString isEqualToString:@"http://www.pleiade.org/images/hubble-m45_large.jpg"]) {
            self.progressBar.progress = 0;
        } else self.progressBar2.progress = 0;

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {}];

    // Start the image download operation
    [op start];

    // Remove the activity indicator
    [loading stopAnimating];
    [loading removeFromSuperview];
}
Community
  • 1
  • 1
Suhit Patil
  • 11,748
  • 3
  • 50
  • 60
0

That is an interesting idea, but I don't think it's a good practice make such a "high coupling" - linking model so tightly to the view.

I'd approach it as - download the data on the background thread as you already do - with NSOperationQueue but save it to some kind of an object; say NSMutableArray that serves as the data source for the table view.

Every time a single operation ends (use completion handlers or KVO to get informed) - update the table view. The update can be done two ways - reloading or updating. I'll leave the choice up to you - you can read further discussion about that in this question.

Community
  • 1
  • 1
Michal
  • 15,429
  • 10
  • 73
  • 104
  • Thanks Michal, if i create a class (NSObjec) and get the NSOperation`s progress into this class and add this object to NSMutableArray , that is declared in Downloader class, is this right solution ?? – iOS_Developer Apr 11 '14 at 08:24
  • one more issue is here with a subclass of NSoperation - dealloc is not getting called . so please give me hint so that i can know about this – iOS_Developer Apr 11 '14 at 12:20
  • I am sorry I can't help you with that just like this. I would have to see the code. – Michal Apr 11 '14 at 12:21