UIActivityIndicatorView doesn't render - iphone

I have reviewed many posts regarding this issue with no success. I have two table view controllers, a source and a destination, both in a navigation controller. When a user taps a cell in the source table view controller, an object is instantiated which makes a web service call that could take several seconds depending on network speed. Once this web service call is made, the segue is executed and navigation moves from the source to the destination. I want an activity indicator to show when this web service call is made. Nothing I have tried for the past several days has worked, even posts marked as successful on this forum. So, there must be something... Here is my code thus far:
Source table view controller header:
#property (strong, nonatomic) UIActivityIndicatorView *activityIndicator;
Source table view controller implementation:
#synthesize activityIndicator;
-(void)loadView {
[super loadView];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:self.activityIndicator];
self.activityIndicator.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSString *stateAbbr;
if([segue.identifier isEqualToString:#"sgShowStateDetail"]){
DetailTableViewController *detailVC = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
NSArray *tempArray = (NSArray*)[groupedStates objectAtIndex:path.section];
NSString *key = [tempArray objectAtIndex:path.row];
stateAbbr = [statesDict objectForKey:key];
[detailVC setStateIdentifier:stateAbbr];
// begin activity indicator here
[self.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
[activityIndicator stopAnimating];
[detailVC setStateGauges:gauges];
// end activity indicator here
}
}
GaugeList is the object that performs the web service call.
Everything works as expected, except there is never an activity indicator. There are no errors. What am I doing wrong? Thanks!

I think you might be using the wrong pattern. The call to the web service has to happen in the background, while the activity indicator has to be shown and hidden on the main thread. Thus
__block NSArray *gauges;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
[detailVC setStateGauges:gauges];
};
};

Here is the code using the method tableView: didSelectRowAtIndexPath: rather than prepareForSegue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
dispatch_async(dispatch_queue_create("", nil), ^ {
NSString *stateAbbr;
DetailTableViewController *detailVC = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailTableViewController"];
NSArray *tempArray = (NSArray*)[groupedStates objectAtIndex:indexPath.section];
NSString *key = [tempArray objectAtIndex:indexPath.row];
stateAbbr = [statesDict objectForKey:key];
[detailVC setStateIdentifier:stateAbbr];
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
[detailVC setStateGauges:gauges];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
[self.navigationController pushViewController:detailVC animated:YES];
});
});
}

Related

UIRefreshControl crashes while refreshing Tableview Controller

I can't refresh my TVC. It crashes when I drag down to refresh. The icon is there, but then it quits. I'm sure its something simple. There are similar questions out there which have not been considered.
Taken from my viewDidLoad method body:
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(refreshInvoked:forState:)
forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:title
attributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:13.0]}];
[self refreshFeed];
Which refers to:
-(void)refreshFeed
{
RSSLoader* rss = [[RSSLoader alloc] init];
[rss fetchRssWithURL:feedURL
complete:^(NSString *title, NSArray *results) {
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader",NULL);
dispatch_async(downloadQueue, ^{
_objects = results;
[self.tableView reloadData];
//completed fetching the RSS
dispatch_async(dispatch_get_main_queue(), ^{
// [(HeaderView*)self.tableView.tableHeaderView setText:title];
// [(ArticleItem*)self.tableView.]
});
});
}];
}
UIRefreshControl is not meant to be added as subview... doing so will get you some trouble and you need to unregister its target on VC dealloc... else you might get some issues, when the UIRefreshControl calls your dead VC (as it doesn't keep a weak or strong reference to your VC)
Change your action method to:
[refreshControl addTarget:self
action:#selector(refreshFeed)
forControlEvents:UIControlEventValueChanged];
Looks like you were pointing to refreshInvoked:forState: which was not present in self.

Sometimes MBProgressHUD is not displaying

I have list of song titles displayed in uitableview along with "Buy" button.when that button is tapped i am showing MBProgressHUD.But sometimes it is not being displayed.also it disables the user-interaction as it is in the below code.
But why it is not displaying the MBProgressHUD sometimes?
Please let me know, Thanks a lot.
Below is the code
-(void) buySong:(UIButton *)button
{
self.view.userInteractionEnabled = NO;
self.navigationController.navigationBar.userInteractionEnabled = NO;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Proessing...";
hud.yOffset = -80;
UITableViewCell *cell = (UITableViewCell *)[[button superview] superview];
NSIndexPath *indexPath = [[self tblViewChildrenPoems] indexPathForCell:cell];
PSSongTags *songTags = [self.songsArray objectAtIndex:indexPath.row];
[ [PurchaseViewController sharedPurchaseManager] startPurchase:songTags];
}
Try this code may be helped you...
In your .h file import the .
#import "MBProgressHUD.h"
the set the delegate .
MBProgressHUDDelegate
After
MBProgressHUD *HUD;
in your .m file // Add this code where you want display ...
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Authorizing...";
[HUD show:YES];
and when your process end use for hide ..
[HUD Hide:YES];
and set hide delegate in your m file also..
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
[HUD release];
HUD = nil;
}
Happy coding...

ScrollView addSubview: very slow

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.

WebView is causing huge memory leak

I have a table view controller in my app. Each cell is the name of a website. When a cell is hit a web view controller is created, passed a url and pushed to the view.
Pretty standard right?
If I go in and out of a web view enough times I begin to get memory warnings until the app crashes.
I can't see anywhere in my implementation where I'm not releasing anything properly. Is there some webview specific best practices or important delegate methods I might have left out?
This is driving me crazy because there is very little code involved and yet I still can't seem to find the problem.
Could somebody help me discover what is causing this memory problem or prehaps refer me to an article or tutorial so I can see how to do this properly?
Table View Controller
#implementation LinkListViewController
#synthesize linksArray;
#synthesize wvcontroller;
#pragma mark -
#pragma mark Initialization
- (void)loadView {
[super loadView];
table = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
[self pushViewController:table animated:YES];
table.tableView.delegate = self;
table.tableView.dataSource = self;
table.title = #"Links"; // Tab Bar Title
[self.view addSubview:table.view];
}
-(id) initWithTabBar {
if ([self init]) {
self.tabBarItem.image = [UIImage imageNamed:#"events.png"];
}
return self;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [linksArray count];;
}
#define LABEL_TAG 7777
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LinkData *ld;
ld=[linksArray objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"Cell";
UILabel *label = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
CGRect frame;
frame.origin.x = 0;
frame.origin.y = 10;
frame.size.width = 100;
frame.size.height = 30;
frame.origin.x = 0;
frame.size.width =290;
label = [[[UILabel alloc] initWithFrame:frame] autorelease];
label.tag = LABEL_TAG;
[cell.contentView addSubview:label];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
label = (UILabel *) [cell.contentView viewWithTag:LABEL_TAG];
}
label.text = [ld.linkname copy];
label.textColor=[UIColor blackColor];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
LinkData *ld=[linksArray objectAtIndex:indexPath.row];
if ([ld.linktype isEqualToString:#"webpage"]) {
if (wvcontroller) {
[wvcontroller release];
wvcontroller=nil;
}
wvcontroller= [[WebViewController alloc]initWithPath:ld.linkurl];
wvcontroller.title=ld.linkname;
[table.navigationController pushViewController:wvcontroller animated:YES];
}
}
Web View Controller
#import "WebViewController.h"
#implementation WebViewController
#synthesize webView;
#synthesize path;
#synthesize showsync;
#synthesize activity;
-(id)initWithPath:(NSString *)thepath
{
if ( [self init]) {
self.path= [thepath copy];
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view setBackgroundColor:[UIColor blackColor]];
[self loadView];
}
return self;
}
- (void)loadView {
//Create a URL object.
webView = [[UIWebView alloc] initWithFrame:self.view.frame];
webView.autoresizesSubviews = YES;
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
//set the web view delegates for the web view to be itself
self.webView.scalesPageToFit = YES;
self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.webView.delegate = self;
//Create a URL object.
NSURL *url = [NSURL URLWithString:path];
//URL Requst Object
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//add the web view to the content view
[self.view addSubview:webView];
//load the URL into the web view.
[webView loadRequest:requestObj];
//[webView release], webView = nil;
activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activity.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activity.center = self.view.center;
[self.view addSubview: activity];
}
/*
If you need to do additional setup after loading the view, override viewDidLoad. */
- (void)viewDidLoad {
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.webView;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[webView release];
[activity release];
webView=nil;
[path release];
[super dealloc];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[activity startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activity stopAnimating];
}
You still hold an extra reference to self.view at the end of initWithPath which should be released.
A bit more explanation: [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] gives you a UIView with a retain count of 1 (since you have just allocated it). Assigning it to self.view bumps its retain count by 1, so it is 2 at the moment. When your controller is deallocated, it takes care of decreasing the retain count of the object in self.view, but the count is still 1, so it never gets deallocated. You should do this:
UIView* myView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = myView;
[myView release];
One way to avoid UIWebView memory problems is to create only one webview one time, and reuse it for the whole life of the application. That is, not release it but reuse it.

returning null inside tableview delegate

HI
I am working on UITablview based project. i like to load a new view when ever a cell got click. i am using following code in didselectRowAtIndexPath delegate method.
The below coding is not showing any error but new view not get load and [self navigationController] is returning null.
inside Viewdidload function [self navigationcontroller] returning proper value. but inside Delegate method [self navigationcontroller] returns null.
/// inside appDelegate class
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.viewController = [[LAMainViewController_iPhone alloc]initWithNibName:#"LAMainViewController_iPhone" bundle:nil];
UINavigationController *controller = [[UINavigationController alloc]initWithRootViewController:viewController];
[window addSubview:controller.view];
[controller release];
[window makeKeyAndVisible];
return YES;
}
/// inside LAmainviewcontroller.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
//self.navigationController.navigationBar.backgroundColor =[UIColor clearColor];// .title=#"test";
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *materialPlistPath = [[NSBundle mainBundle]pathForResource:#"materials" ofType:#"plist"];
materialList = [[NSArray alloc]initWithContentsOfFile:materialPlistPath];
materialTable.backgroundColor = [UIColor blackColor];
NSLog(#" dud kiad navigationController %#", self.navigationController);
//2010-10-20 15:22:03.809 LabAssistant[17368:207] dud kiad navigationController <UINavigationController: 0x5f3b160>
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
self.navigationController.navigationBarHidden = YES;
NSIndexPath *indexPath = [materialTable indexPathForSelectedRow];
[materialTable deselectRowAtIndexPath:indexPath animated:YES];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
LAMaterialPropertiesViewController_iPhone *materialPropertyListView = [[[LAMaterialPropertiesViewController_iPhone alloc] initWithNibName:#"LAMaterialPropertiesViewController_iPhone" bundle:nil] autorelease];
materialPropertyListView.chemicalName = [[materialList objectAtIndex:[indexPath row]] objectForKey:#"materialProperty"];
[[self navigationController] pushViewController:materialPropertyListView animated:YES];
NSLog(#"%#",[self navigationController]);
///2010-10-20 16:20:42.634 LabAssistant[17656:207] navigationController (null)
}
please help me to fix this issue.
thanks!
Remove the autorelease from the init statement. Actually the viewcontroller is getting released before it gets pushed.
instead of
LAMaterialPropertiesViewController_iPhone *materialPropertyListView = [[[LAMaterialPropertiesViewController_iPhone alloc] initWithNibName:#"LAMaterialPropertiesViewController_iPhone" bundle:nil] autorelease];
try this
LAMaterialPropertiesViewController_iPhone *materialPropertyListView = [[LAMaterialPropertiesViewController_iPhone alloc] initWithNibName:#"LAMaterialPropertiesViewController_iPhone" bundle:nil];
Hope this will solve your problem.
I think the table view delegate is called before the navigation controller is set to the view controller.
Can you try reloading the tableview [tableview reloadData]; in viewWillAppear or viewDidAppear?