ScrollView addSubview: very slow - iphone

I am using a scrollview to display a viewcontrollers view. if the user reaches the end of the cached views my method reloads the new views. My NSLogs say that the method is finished but it takes additional 5 seconds to display the view.
I think that the [scrollView addSubview:vc.view] is very very slow but I found nothing to improve it.
the whole method gets called in -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollView.userInteractionEnabled = NO;
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicator setFrame:CGRectMake((320.f*index)+135.f, 151, 50, 50)];
[activityIndicator setHidesWhenStopped:YES];
[activityIndicator startAnimating];
[scrollView addSubview:activityIndicator];
MBBAppDelegate *delegate = (MBBAppDelegate *)[UIApplication sharedApplication].delegate;
[delegate fetchDealsWithFilter:dealFilter fromIndex:index toIndex:(index+3) onSuccess:^(id object){
MBBDealList *list = object;
int i = 0;
ProductDetailViewController *vc;
for (MBBDeal *deal in [list deals]) {
NSLog(#"start %i",i);
int indexInArray = i;//[list.deals indexOfObject:deal];
if (indexInArray+index >= numDeals) {
return;
}
vc = [[ProductDetailViewController alloc] init];
//fetch the deal and insert
vc.numberOfDeals = numDeals;
vc.dealIndex = index+1+indexInArray;
vc.dealFilter = dealFilter;
vc.deal = deal;
vc.view.frame = CGRectMake(320.f*(index+indexInArray), 0.f, 320.f, 436.f);
[scrollView addSubview:vc.view];
[productDetailViewControllers insertObject:vc atIndex:(index+indexInArray)];
i++;
}
[activityIndicator stopAnimating];
scrollView.userInteractionEnabled = YES;
}];
}
Does anyone know how I can improve my method?

What I can understand from your problem is that, the activity indicator that you have used to show the data fetch process is not used properly.
You data fetch process is still working, even after the activity indicator disappears.
You can do 2 things for that:
ether call the data fetch method in background using performSelectorInBackground method or place the activity indicator in the app delegate where you have created your data fetch method.

Related

UIActivityIndicator not displayed

I have a FirstView loaded with tableView and when a accessory button of tableviewCell is tapped then it goes to SecondView.The data in SecondView is loaded from service url and so it takes time.So I need to show activityIndicator when accessorybutton is tapped, stop it after loading the whole data .BUt I couldnot see the activityindicator getting displayed.
This is the code Im working on :
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.color = [UIColor redColor];
[scrollView addSubView:activityIndicator];
[activityIndicator startAnimating];
activityIndicator.frame=CGRectMake(140, 195, 37, 37);
[activityIndicator startAnimating];
SecondView *secView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
secView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *name1 = (UILabel*)[cell viewWithTag:111];
secView.provName = [name1 text];
[self presentModalViewController: secView animated:NO];
[secView release];
}
Where I m going wrong?
EDIT:
SecondView:
-(void)viewWillAppear:(BOOL)animated
{
activityIndictr = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndictr.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
activityIndictr.color = [UIColor redColor];
[testscroll addSubview:activityIndictr];
[activityIndictr startAnimating];
}
-(void)viewDidLoad
{
[super viewDidLoad]
// I m calling many service urls(10) and assigning to labels and tableview
[activityIndictr stopAnimating];
}
You should call the activity indicator in the SecondView's ViewWillAppear , so that immediately after pushing in this view the activity indicator starts and then dismiss it when all the data is parsed from the url.
This is because the Second View Controller will be pushed almost immediately and the data will take time to load
You allocate two activity indicators, throw the first one away, then start animating the second one twice and never add any activity indicator into any existing view. No wonder it’s not showing up. Try [[secView view] addSubview:activityIndicator] or something similar.
Do this in viewWillAppear of SecondView :
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
Again I have updated the answer.
put this code in appdelegate And define static object in appdelegate like below
static UIActivityIndicatorView *activityView;
+(void)showActivityIndicator{
if (!activityView) {
activityView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.center = CGPointMake(160, 230);
[activityView startAnimating];
UIWindow *win = [UIApplication sharedApplication].keyWindow;
[win addSubview:activityView];
}
}
+(void)removeActivityIndicator{
if ([activityView superview]) {
[activityView removeFromSuperview];
activityView = nil;
}
}
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
//global static activity indicator... you can access from any other view controlller
[AppDelegate showActivityIndicator];
}
And after getting response
[AppDelegate removeActivityIndicator];

Utilizing a UIActivityIndicatorView and CorePlot-CocoaTouch causes memory prblem

Utilising CorePlot-Cocoa Touch in an IOS5.1 app. Since the setting up of the scatterplots, dataForPlots, legends etc takes time, decided to include a UIActivityIndicatorView to indicate something is happening to the user.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
progressInd = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
progressInd.center = self.view.center;
[progressInd sizeToFit];
progressInd.hidden = NO;
progressInd.alpha = 1.0;
[self.view addSubview:progressInd];
[progressInd startAnimating];
[self.view bringSubviewToFront:progressInd];
[self performSelectorInBackground:#selector(DoMakeupPlot) withObject:nil];
}
- (void)DoMakeupPlot
{
… set up plot
… including datasource and delegate
[progressInd stopAnimating];
[progressInd removeFromSuperview];
progressInd = nil;
}
Now this seems to work on occasion, however it's apparent that there becomes 2 Threads calling the plot datasource routines:
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
which does on occasion cause memory problems and the app crashes.
Experimented exiting these 2 Threads from within the 2 above routines, but this causes other problems.
Now prior to using this UIActivityIndicatorView, whereby the 2 routines above are called from the MainThread, all is good.
Also tried this with the MBProgressHud, and obviously have the same problem.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Loading";
HUD.detailsLabelText = #"plot data";
HUD.square = YES;
[HUD showWhileExecuting:#selector(DoMakeupPlot) onTarget:self withObject:nil animated:YES];
}
How do I remove the Thread which performs the number crunching, whilst the MainThread does the UIActivityIndicatorView, after it has done the setting up?
Help appreciated.
Don't set the datasource until -DoMakeupPlot finishes. That way the plot doesn't try to load data from the datasource that's not ready yet.

PageController and TableView

I have a page controller and that method pageAction defined like this :
-(void)pageAction:(UIPageControl*)control
{
NSLog(#"page changed");
[self getVehicules];
[self.tableViewVehiculesPossedes release];
int page = pageControlVehiculePossedee.currentPage;
NSLog(#"page %d", page);
[self loadScrollViewWithPage:page];
CGRect frame = pageControlVehiculePossedee.frame;
frame.origin.x = (vosvehiculeScrollView.frame.size.width * page);
[vosvehiculeScrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
Every time I change the page I need to display a tableview with some labels. Here is the code :
- (void)viewDidLoad
{
[super viewDidLoad];
[self getVehicules];
vosvehiculeScrollView.pagingEnabled = YES;
vosvehiculeScrollView.showsHorizontalScrollIndicator = NO;
vosvehiculeScrollView.showsVerticalScrollIndicator = NO;
vosvehiculeScrollView.scrollsToTop = NO;
pageControlVehiculePossedee.numberOfPages=[vehiculesPossede count];
pageControlVehiculePossedee.currentPage=0;
[self loadScrollViewWithPage:0];
[pageControlVehiculePossedee addTarget:self action:#selector(pageAction:) forControlEvents:UIControlEventValueChanged];
votreVehiculeLabel.text=#"Votre véhicule";
vehiculesPossedesArray = [[NSMutableArray alloc] initWithObjects:#"Annee modele", #"Transmission",#"Carburant", nil];
}
- (void) loadScrollViewWithPage: (int) page {
if (page < 0) return;
if (page >= [vehiculesPossede count]) return;
tableViewVehiculesPossedes=[[UITableView alloc] initWithFrame:CGRectMake(3, 80, 315, 171) style:UITableViewStyleGrouped];
tableViewVehiculesPossedes.tag=page;
tableViewVehiculesPossedes.bounces=NO;
tableViewVehiculesPossedes.backgroundColor=[UIColor clearColor];
[tableViewVehiculesPossedes setDelegate:self];
[tableViewVehiculesPossedes setDataSource:self];
[self.vosvehiculeScrollView addSubview:tableViewVehiculesPossedes];
nameVehiculeLabel.text=[[vehiculesPossede objectAtIndex:page] valueForKey:#"modele"];
self.transmissionString=[[vehiculesPossede objectAtIndex:page]valueForKey:#"transmision"];
self.carburantString=[[vehiculesPossede objectAtIndex:page] valueForKey:#"carburant"];
self.anneeModelString=[[vehiculesPossede objectAtIndex:page] valueForKey:#"modele_annee"];
self.anneeString=[[vehiculesPossede objectAtIndex:page]valueForKey:#"annee"];
if(page==0){
NSLog(#"0");
self.transmissionString=#"ttt";
}
else NSLog(#"1");
}
The problem is that even I put [self.tableViewVehiculesPossedes release]; on the change page method, the tableView appear overlay and the text from labels are overlay. What can I do with the tableview to make it dissapear when a new page will be display?
Please help me..I spent a lot of time with this :|
If I get it correctly I think you should keep an ivar to the table you create with the alloc in loadScrollViewWithPage, and when switching page you should removing it from the view by calling :
[mytableview removeFromSuperview];
And most likely your should take care of releasing it as well as I can't see it in your code.

Loading animation Memory leak

I have written network class that is managing all network calls for my application. There are two methods showLoadingAnimationView and hideLoadingAnimationView that will show UIActivityIndicatorView in a view over my current viewcontroller with fade background. I am getting memory leaks somewhere on these two methods. Here is the code
-(void)showLoadingAnimationView
{
textmeAppDelegate *textme = (textmeAppDelegate *)[[UIApplication sharedApplication] delegate];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
if(wrapperLoading != nil)
{
[wrapperLoading release];
}
wrapperLoading = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
wrapperLoading.backgroundColor = [UIColor clearColor];
wrapperLoading.alpha = 0.8;
UIView *_loadingBG = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
_loadingBG.backgroundColor = [UIColor blackColor];
_loadingBG.alpha = 0.4;
circlingWheel = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
CGRect wheelFrame = circlingWheel.frame;
circlingWheel.frame = CGRectMake(((320.0 - wheelFrame.size.width) / 2.0), ((480.0 - wheelFrame.size.height) / 2.0), wheelFrame.size.width, wheelFrame.size.height);
[wrapperLoading addSubview:_loadingBG];
[wrapperLoading addSubview:circlingWheel];
[circlingWheel startAnimating];
[textme.window addSubview:wrapperLoading];
[_loadingBG release];
[circlingWheel release];
}
-(void)hideLoadingAnimationView
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
wrapperLoading.alpha = 0.0;
[self.wrapperLoading removeFromSuperview];
//[NSTimer scheduledTimerWithTimeInterval:0.8 target:wrapperLoading selector:#selector(removeFromSuperview) userInfo:nil repeats:NO];
}
Here is how I am calling these two methods
[NSThread detachNewThreadSelector:#selector(showLoadingAnimationView) toTarget:self withObject:nil];
and then somewhere later in the code i am using following function call to hide animation.
[self hideLoadingAnimationView];
I am getting memory leaks when I call showLoadingAnimationView function. Anything wrong in the code or is there any better technique to show loading animation when we do network calls?
The method showLoadingAnimationView returns a non auto-released view (retainCount -> 1), that you later (I assume) add to another view (retainCount -> 2).
In hideLoadingAnimationView, you only remove the view from its superview (retainCount -> 1). There is a missing release in this method. That means that you should not call release in the showLoadingAnimationView.

UIActivityIndicator not showing up

I have implemented a UIActivityIndicator that shows up in one part of my program but not another. I have the activity indicator come up while i am loading a table, however, i am trying to get it to start animating again after the user has clicked a button and is waiting for the table to reload. The table reloads, but no indicator. Here is the code.
- (void)viewWillAppear:(BOOL)animated {
CGRect frame = CGRectMake (120.0, 185.0, 80, 80);
activity = [[UIActivityIndicatorView alloc] initWithFrame: frame];
activity.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[activity startAnimating];
[navigationUpdateFromDetail.window addSubview: activity];
[super viewWillAppear:animated];
}
It comes up for that part. However, for the next part it does not want to seem to come up.
- (IBAction) btnGreaterTen_clicked :(id)sender {
self.searchDistance = [NSNumber numberWithDouble : 10];
CGRect frame = CGRectMake (120.0, 185.0, 80, 80);
activity = [[UIActivityIndicatorView alloc] initWithFrame: frame];
activity.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[navigationUpdateFromDetail.window addSubview: activity];
[activity startAnimating];
NSLog(#" search value after change %#", [searchDistance description]);
[self getSetDisplay];
[activity stopAnimating];
}
That button changes a variable and is suppose to start the animation, but it does not. I have changed the color to make sure it was not just blending in, so that is not the solution. I tried to recreate the same object, but still no luck.
Thank you in advance.
That won't work, because the animation will only show when the main application loop is "running". In your code, you're blocking the main thread by calling [self getSetDisplay].
You should load your data asynchronously to make this work (in a background thread). Then you can call startAnimating, start your thread, and when the thread finishes, stop the animation.
This has been bugging me for ages, and I just found that when using a search display controller I had to add the activity indicator as a subview of the search results to get it to show. In my viewDidLoad, I put...
// create activity indicator
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.searchDisplayController.searchResultsTableView addSubview:activityIndicator];
When I want to start animating, i put...
[activityIndicator setCenter:CGPointMake(self.searchDisplayController.searchResultsTableView.frame.size.width/2.0f, self.searchDisplayController.searchResultsTableView.frame.size.height/2.0f)];
[activityIndicator startAnimating];
Hope this helps someone.
try adding
activity.hidden = NO;
just before
[activity startAnimating];