iOS7: Multi-UITableview rendering lag - ios

I have a viewcontroller in a universal app which has 5 coloumns (UITableview). Initially I fetch data from CoreData and then categorise it in 5 NSArrays. After that I call all 5 UITableViews to reload via following code.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[_tvLeftMost reloadData];
}];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[_tvLeft reloadData];
}];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[_tvCenter reloadData];
}];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[_tvRight reloadData];
}];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[_tvRightMost reloadData];
}];
on both IOS7&8(iPAD3) the data is fetched in 0.5 secs. But reload tables takes 5 secs on iOS8 and 20+ secs on iOS7. The UITableView's cell are not complex and only involve a local UIImage & a UILabel. How can I decrease rendering time on iOS7?

Try to reload your UITableView in below way -
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
If your UITableView load image from web url , then it must be async image loading. Please check this tutorial for async image loading.

Related

Why does AFNetworking load database so slowly in iOS [duplicate]

I have a class that runs similar to the AFHTTPSessionManager component of this tutorial http://www.raywenderlich.com/59255/afnetworking-2-0-tutorial
However, [self.tableView reloadData] is not working for me.
I have the manager implemented as so:
-(void) refresh{
manager = [[AFHTTPSessionManager...] iniwithBaseURL:...];
[manager Get:... parameters:... success:^(NSURLSessionDataTask *task, id responseObject){
//test success values in responseObject
if(test){
//Get table data
[self.tableView reloadData];
}
}
....
}
However if I run [self.tableView reloadData] in a separate function afterwards, it works just fine.
Why is this happening, instead of how it should in the tutorial?
Always reload on the main queue:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
write the [self.tableView reloadData];in the main queue.
dispatch_sync(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});

How to Call text posting method after image posting method get done in IOS

I used below code for calling image posting first and then text posting upon completion of image posting method...
-(IBAction)btnChooseClecked:(id)sender
{
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{
[self sendImage];
}];
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];//2.0
[self sendText];
}];
///(OR) i used below code also
dispatch_async(dispatch_get_main_queue(), ^{
[self sendImage];
// inside sendImage method I am calling sendText as [self performSelector:#selector(sendText) withObject:nil afterDelay:0.2];
})
}
-(void)sendImage
{
NSData *imageData = UIImageJPEGRepresentation([appDelegate scaleAndRotateImage:imageSelected.image], 0.0);
[appDelegate.hub invoke:#"Send" withArgs:#[([imageData respondsToSelector:#selector(base64EncodedStringWithOptions:)] ? [imageData base64EncodedStringWithOptions:kNilOptions] : [imageData base64Encoding])]];
[self performSelector:#selector(sendText) withObject:nil afterDelay:0.5];
}
But sometimes it is working fine but sometimes text is posting first instead of image. No delegate method is called after completion of first..As we used different API for performing post method.
Please suggest any ideas where I am going wrong..Any alternatives for above..
Thanks in Advance..

Sending NSOperationQueue to UITableView as a DataSource

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.
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.
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];
}
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.

iOS TableView with dynamic data and background picture loading

I have a view controller with a three segmented button at the top, and below it a table view. When the user clicks a button, a URL is called, and the appropriate data is loaded into the cells. Then, the appropriate images are loaded in the background and the tableview is updated. The issue lies when the user clicks a different button AND the images from the last set of data haven't finished loading. Initially I prevented the user from clicking a different button, until all of the first data was done loading. But this was really slow. Then I tried waiting until all the images were done being loaded before updating the tableview, but that is also pretty slow. Is there a better way of doing this besides making three tableviews? Below is how I get images.
- (void) getImageLinks:(int)number{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[imageLinks objectAtIndex:number]];
[request setAllHTTPHeaderFields:#{#"User-Agent": #"Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"}];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if([data length] > 0){
UIImage *image = [UIImage imageWithData:data];
if(image){
[images addObject:image];
dispatch_async(dispatch_get_main_queue(), ^{
if(number<[imageLinks count]-1){
[self getImageLinks:number+1];
}else{
isRefreshing = NO;
_segmentedControl.userInteractionEnabled = YES;
NSLog(#"end refreshing");
[_tableView reloadData];
[refreshControl endRefreshing];
}
});
}else{
NSLog(#"NO IMAGE");
}
}
}];
You haven't used background Queue for Requesting data. Just Call the request to the URL in Background queue and save the Image data. Then You can Synchronously call the Image to update to ImageView in Main queue using dispatch_sync() method.

UITableView reloadData is slow

I have a function that connects to the internet and then refreshes the cells in the table.
My function is:
- (void) updateMethod
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = #"Data request queue";
[queue addOperationWithBlock:^{
//neither of these delay the responsiveness of the table
[columnArrayBackground removeAllObjects];
[self getColumnDataBackground];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
for (int i=0; i < 6; i++) {
columnArray[i] = columnArrayBackground[i];
};
//THIS ONE LINE CAUSES DELAYS
[homeTable reloadData];
}];
}];
}
Everything is super speedy EXCEPT for [homeTable reloadData]. When I comment that out, I have quick response. When I uncomment it, my cell response lags sometimes by a few seconds!
My other reloadData calls do not delay my app. Am I not implementing NSOperationQueue correctly?
Remove the queues from your update method and leave only what updates the table. Under the action that refreshes your table add this code. Where the updateMethod is the code that updates the table. Only when you are back on the main thread do you reload the data. Hope this helps!
//perform on new thread to avoid the UI from freezing
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^{
//background thread code
[self performSelector:#selector(updatemethod:) withObject:nil];
dispatch_async(dispatch_get_main_queue(),
^{ //back on main thread
[self.tableView reloadData];
});});

Resources