I am trying to learn to use dispatch_get_global_queue to perform a web call asynchronously. Basically, I need to update the User Interface depending on the user's location. I started using dispatch_get_global_queue because the user interface was unresponsive while the web call was performed.
Now, my problem is that the buttons do not appear correctly when buttonUpdate is called. One button is supposed to be black, and the other is green. However, now they both appear the default blue. Also, the words/title of the buttons do not appear until I click on one of them. Anyone know why? Thank you!
I have this method called preButtonUpdate that calls the buttonUpdate method asynchronously:
-(void)preButtonUpdate {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
[self buttonUpdate];
});
}
The preButtonUpdate method is called in viewDidAppear and appReturnsActive:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self preButtonUpdate];
//other code
}
- (void)appReturnsActive {
[myTimer invalidate];
myTimer = nil;
//ONLY WANT TO PERFORM THE UPDATE IF VIEWING THE PROFILE VIEW CONTROLLER
UIViewController *currentVC = self.navigationController.visibleViewController;
NSString * name = NSStringFromClass([currentVC class]);
if ([name isEqualToString:#"ProfileViewController"]) {
[self preButtonUpdate];
}
}
Then, the preButtonUpdate calls the buttonUpdate method, which performs the web query and updates the user interface:
-(void) buttonUpdate {
[locationManagerProfile stopUpdatingLocation];
NSString *userLatitude =[(PDCAppDelegate *)[UIApplication sharedApplication].delegate
getUserLatitude];
NSString *userLongitude =[(PDCAppDelegate *)[UIApplication sharedApplication].delegate
getUserLongitude];
NSString *placeLatitude = [[NSUserDefaults standardUserDefaults]
stringForKey:#"savedLatitude"];
NSString *placeLongitude = [[NSUserDefaults standardUserDefaults]
stringForKey:#"savedLongitude"];
NSString *distanceURL = [NSString stringWithFormat:#"http://www.website.com/page.php?
lat1=%#&lon1=%#&lat2=%#&lon2=%#",userLatitude, userLongitude, placeLatitude,
placeLongitude];
NSData *distanceURLResult = [NSData dataWithContentsOfURL:[NSURL
URLWithString:distanceURL]];
NSString *distanceInFeet = [[NSString alloc] initWithData:distanceURLResult
encoding:NSUTF8StringEncoding];
if ([distanceInFeet isEqualToString:#"1"]) {
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithTitle:#"Button A"
style:UIBarButtonItemStyleBordered target:self action:#selector(actionA)];
self.navigationItem.rightBarButtonItem = btnGo;
[self.navigationItem.rightBarButtonItem setTintColor:[UIColor
colorWithRed:44.0/255.0 green:160.0/255.0 blue:65.0/255.0 alpha:1.0]];
UIBarButtonItem *btnGoTwo = [[UIBarButtonItem alloc] initWithTitle:#"Button B"
style:UIBarButtonItemStyleBordered target:self action:#selector(actionB)];
self.navigationItem.rightBarButtonItem = btnGoTwo;
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:btnGo,
btnGoTwo, nil];
}
if ([distanceInFeet isEqualToString:#"0"]) {
UIBarButtonItem *btnGo = [[UIBarButtonItem alloc] initWithTitle:#"Button C"
style:UIBarButtonItemStyleBordered target:self action:#selector(actionC)];
self.navigationItem.rightBarButtonItem = btnGo;
[self.navigationItem.rightBarButtonItem setTintColor:[UIColor
colorWithRed:44.0/255.0 green:160.0/255.0 blue:65.0/255.0 alpha:1.0]];
UIBarButtonItem *btnGoTwo = [[UIBarButtonItem alloc] initWithTitle:#"Button B"
style:UIBarButtonItemStyleBordered target:self action:#selector(actionB)];
self.navigationItem.rightBarButtonItem = btnGoTwo;
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:btnGo,
btnGoTwo, nil];
}
}
UI Update is always done on the main thread. So keep your UI update code out of the despatch queue
Keep [self buttonUpdate]; out of the dispatch_async block
-(void)preButtonUpdate {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
[self buttonUpdate];
});
}
Unblocking Your User Interface - Apple Developer
EDIT:
Put the if condtion code just outside the dispatch_async block
Related
I have added a navigation controller in iphone app from my home screen it takes to a tableview from the table view it takes to the detail.I am able to navigate between the views back and forth.what I want is navigate directly from detail view to my home screen.Is there any possibility to do that?
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.hidesBackButton = TRUE;
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:#selector(save)]; self.navigationItem.leftBarButtonItem = saveButton;
id1 = [[NSUserDefaults standardUserDefaults] valueForKey:#"id1"];
theTitle = [[NSUserDefaults standardUserDefaults] valueForKey:#"theTitle"];
self.title=theTitle;
NSLog(#"hi %#", id1);
hello=#"hello";
NSLog(#"ahhhha sdfgs :%#",theTitle);
urlAddress = [NSString stringWithFormat:#"http://dev-parkguiden.knutpunkten.se/Api/GetPark?parkid=%#",self.id1];
baseURL =[[NSURL URLWithString:urlAddress]retain];
jsonData=[NSData dataWithContentsOfURL:baseURL];
NSDictionary *items=[NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
boom=[items objectForKey:#"description"];
latitude=[items objectForKey:#"latitude"];
longitude=[items objectForKey:#"longitude"];
NSLog(#"retard:%#",latitude);
NSLog(#"retard:%#",longitude);
NSString *html = [NSString stringWithFormat:#"<html><body><p>%#</p></body></html>", boom];
[self.webview loadHTMLString:html baseURL:nil];
[[NSUserDefaults standardUserDefaults] setValue:latitude forKey:#"lat"];
[[NSUserDefaults standardUserDefaults] setValue: longitude forKey:#"lot"];
[[NSUserDefaults standardUserDefaults] setValue: theTitle forKey:#"title"];
}
[self.navigationController popToRootViewControllerAnimated:YES];
this will pop back to the rootviewController of navigation controller
you have to just set custom back button and set button click event
// hide back button first
self.navigationItem.hidesBackButton = TRUE;
/// Add new Back Button
UIButton *back = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
back.frame = CGRectMake(0, 0, 50, 32);
[back setShowsTouchWhenHighlighted:TRUE];
[back setBackgroundImage:[UIImage imageNamed:#"backBtn.png"] forState:UIControlStateNormal];
[back addTarget:self action:#selector(backBtnTap:) forControlEvents:UIControlEventTouchDown];
UIBarButtonItem *backBtn = [[UIBarButtonItem alloc] initWithCustomView:back];
self.navigationItem.leftBarButtonItem = backBtn;
/// Press button event to go to root or say home page
-(void)backBtnTap:(id)sender{
[self.navigationController popToRootViewControllerAnimated:YES];
}
I have a memory leak that I do not understand. I am switching views with a segmentcontrol like this:
- (void)didChangeSegmentControl:(UISegmentedControl *)control {
if (self.activeViewController) {
[self.activeViewController viewWillDisappear:NO];
[self.activeViewController.view removeFromSuperview];
[self.activeViewController viewDidDisappear:NO];
}
self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex];
[self.activeViewController viewWillAppear:NO];
[self.containerView addSubview:self.activeViewController.view];//Here is the memory leak
[self.activeViewController viewDidAppear:NO];
[self BuildBottomBarButtons];
}
I leak appears in Instruments and I do not have any idea why...
Thanks!!!
Edit:
The "BuildBottomBarButtons":
-(void) BuildBottomBarButtons{
//create toolbar using new
UIToolbar *toolbar = [UIToolbar new];
toolbar.barStyle = UIBarStyleBlackTranslucent;
[toolbar sizeToFit];
toolbar.frame = CGRectMake(0, 330, 320, 50);
//Add buttons
UIBarButtonItem *systemItem1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(shareClicked)];
UIBarButtonItem *systemItem2 = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"scroll left.PNG"] style:UIBarButtonItemStylePlain target:self action:#selector(upClicked)];
UIBarButtonItem *systemItem3 = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"scroll right.PNG"] style:UIBarButtonItemStylePlain target:self action:#selector(downClicked)];
//Use this to put space in between your toolbox buttons
UIBarButtonItem *fixItem50 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
UIBarButtonItem *fixItem70 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
fixItem50.width = 50;
fixItem70.width = 64;
//Add buttons to the array
NSArray *items = [NSArray arrayWithObjects: systemItem1, fixItem70, systemItem2, fixItem50,systemItem3, nil];
//release buttons
[systemItem1 release];
[systemItem2 release];
[systemItem3 release];
[fixItem70 release];
[fixItem50 release];
//add array of buttons to toolbar
[toolbar setItems:items animated:NO];
[self.containerView addSubview:toolbar];
[toolbar release];
}
And the "self.segmentedViewControllers" init method is:
- (NSMutableArray *)segmentedViewControllerContent {
JobGeneralDetailsController * controller1 = [[JobGeneralDetailsController alloc] initWithSelectedRowID:selectedRowID andWithJobBoardID:jobBoardId andWithJobDetails:jobDetails];
[controller1 setViewType:jobDetailsViewType];
//initWithParentViewController:self];
JobMapDetailsController * controller2 = [[JobMapDetailsController alloc] initWithJobDetails:jobDetails];//[[AustraliaViewController alloc] initWithParentViewController:self];
[controller1 setJobMapDetailsController: controller2];
JobReviewsController *controller3 = [[JobReviewsController alloc] initWithStyle:UITableViewStyleGrouped];
[controller3 setJobDetails:jobDetails];
[controller3 setViewType:jobDetailsViewType];
[controller1 setJobReviewsController: controller3];
NSMutableArray * controllers = [NSMutableArray arrayWithObjects:controller1, controller2, controller3,nil];
[controller1 release];
[controller2 release];
[controller3 release];
return controllers;
}
The only line I could point to is [self BuildBottomBarButtons];
Looking at your code the only problem I can see is in the [self BuildBottomBarButtons]
It looks like you are adding the toolbar to the container view everytime you switch view controllers.
What type of object does Instruments say is leaking, is it possible to see a screen shot of your instruments screen showing the leaked objects?
-(void)reloadView{
NSLog(#"IN RELOAD VIEW ");
[[self tableView] reloadData];
}
- (void)viewDidLoad {
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
[self navigationItem].rightBarButtonItem = barButton;
[activityIndicator startAnimating];
[self callStudentsWebService];
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
[self setTitle:#"Students"];
self.navigationController.toolbarHidden = NO;
self.navigationController.toolbar.barStyle = UIBarStyleBlack;
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithTitle:#"Add Student" style:UIBarButtonItemStyleBordered target:self action:#selector(addStudent)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *import = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:#selector(addStudent)];
NSArray* toolbarItems = [NSArray arrayWithObjects:add,flexible,import, nil];
self.toolbarItems = toolbarItems;
}
Above is my Code in a Class which is a subclass of UITableViewController.
Now my problem is when I come onto the screen First Time it get the records from web service from the method [self callStudentsWebService] . Now i have a button in uitoolbar in the same view which updates the list . I am calling the reloadView method to refresh the List but it calls the numberOfRowsInSection and viewDidLoad method but does not call cellForRowAtIndexPath method. But when i goto other screen and come back again it does refresh my List from start.
What could be the reason ?? Please help i am new in iPad Development. And i m doing all this in iPad.
Thanks alot
EDITED
#interface StudentsList : UITableViewController {
DetailViewController *detailViewController;
UIToolbar *toolbar;
UIActivityIndicatorView *activityIndicator;
}
May be your data.count is 0? If there is some data it should call cellForRowAtIndexPath after [[self tableView] reloadData];
Do the refresh code in another separate method -(void)refreshData then call this whenever you want such as in -viewDidLoad or on a button tap...
Try to call -(void)reloadView from
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self reloadView];
}
I have a modalviewcontroller and have two buttons on it: Cancel and Save. There is a UITextField which is editable.
Whenever I click on save button I do save it but the text doesnot get save because when I click on the button to open the modalviewcontroller, the text disappears. Dont know whats wrong with my code.
Here is my code :
- (void)viewWillAppear:(BOOL)animated {
self.cancel = self.navigationItem.leftBarButtonItem;
self.save = self.navigationItem.rightBarButtonItem;
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(cancelAction)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:#"Save" style:UIBarButtonItemStylePlain target:self action:#selector(saveAction)];
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];
[super viewWillAppear:animated];
}
-(IBAction) cancelAction{
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
-(IBAction) saveAction{
NSString *text = [textFieldBeingEdited text];
[textFieldBeingEdited setText:text];
[self setDescription:text];
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
I am not sure if I have to use the following code to save the text in textfield :
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self dismissModalViewControllerAnimated:YES];
}
I don't see in your code anywhere that you are setting the text in the UITextField when the view appears. You can add some code to your viewWillAppear method to set the text when the view appears, such as:
[textField setText:[self description]];
(It looks like you are storing the NSString in the description variable.)
Also, if this is some kind of string that could be considered a User Default, you can store the string there. I've used this before and it populates my UITextField nicely.
Code Example:
-(void)viewDidLoad
{
stringValue = [[NSUserDefaults standardUserDefaults] stringForKey:#"string"];
[textField setText:stringValue];
}
-(IBAction)saveAction
{
stringValue = [textField text];
[[NSUserDefaults standardUserDefaults] setObject:stringValue forKey:#"string"];
}
Here in my application i created a leftbarbuttonitem programatically in viewWillAppear methos, i have two click twice to work this, my code is as follows.
Code for creating UIBarButtonItem(left bar button)
goingBackButton = [[UIBarButtonItem alloc] init];
goingBackButton.title = #"Back";
goingBackButton.target = self;
goingBackButton.action = #selector(backAction);
self.navigationItem.leftBarButtonItem = goingBackButton;
[goingBackButton release];
Action code
- (IBAction) backAction {
NSLog(#"Inside the backAction of uploadViewController");
[self.navigationController popViewControllerAnimated:YES];
NSLog(#"Inside the backAction1 of uploadViewController");
}
Try the below code:
UIBarButtonItem *bar = [[UIBarButtonItem alloc]initWithTitle:#"back" style:UIBarButtonItemStyleDone target:nil action:#selector(back)];
self.navigationItem.leftBarButtonItem = bar;
[bar release];
-(void)back
{
[self.navigationController popViewControllerAnimated:YES];
}