I am fetch data from the server to display in a picker view. If the API has not returned i display Loading... in the picker view.
Here is my use case:
API Call made to the server
User clicks button to show picker view.
Picker View is shown and displays the text LOADING...
API call returns. i call [self.seasonEpiPickerView reloadAllComponents];
Nothing happens. Basically since the picker view is already loaded and being shown on the screen it is not updating its data. How can i update the data of a picker view that is already being displayed?
You need
In .h file
#interface ViewController : UIViewController
<UIPickerViewDataSource,UIPickerViewDelegate>
In .m file set delegate and datasource
yourpicker.delegate = self;
yourpicker.datasource = self;
may this help you
Solved it: My response from the server was not on the main thread. I had put a test thread to delay UI updates for testing. I removed the test code and executed the updateUI lines from the main thread and everything works with the same above code.
Related
Here is the scenario:
OrderVC have a table view on which if you right swipe it shows some
options. In which one of the option is Checkout.
When user taps on Checkout it opens up CheckoutVC which has a parent class OrderVC.
Here user can add some text and can attach multiple images and can also save this data as draft which is achieved using core data. But when user submit the bill I'm using AFNetworking to call web api and upload images using AFMultipartFormData. All of this process is taking place on a background thread i.e.dispatch_async
I can't update UI in dispatch_get_main_queue because methods are calling other method from within see this question it'll clear this point. So it calls the update UI right after first method is finished.
Question
As long as background thread is working it should show activity indicator on the cell. When it's finished and the response is success in CheckoutVC it should reload the tableView of OrderVC.
Solution I triedI tried to run a for loop in allOrderID which are the ID's I get via web api hit of active orders. Then I made a call to MR_findFirstByAttribute to find if any of the fetched OrderID exist in drafts. There is an attribute isSending in DraftOrderInfo entity which is a BOOL and I truns it to true when checkout enters background thread. So if isSending is true I show the activity indicator in place of a UIView I created.
for (NSString *orderID in allOrderId) {
DraftOrderInfo *dpi = [DraftOrderInfo MR_findFirstByAttribute:#"orderID" withValue:orderID];
if (dpi.isSending) {
orderCell.rightUtilityButtons = nil;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.center = CGPointMake(orderCell.orderStatusIndicatorBadgeView.frame.origin.x-2, orderCell.orderStatusIndicatorBadgeView.frame.origin.y-8);
[activityView startAnimating];
[orderCell.orderStatusIndicatorBadgeView addSubview:activityView];
}
}
The output I get is that when OrderVC is loaded it started showing activity indicator on all the cells.
First, your following point is not valid. Read the comments on the question:
can't update UI in dispatch_get_main_queue because methods are calling
other method from within see this question it'll clear this point. So
it calls the update UI right after first method is finished.
Back to the problem. There is multiple good practices to use. One of them:
Add the UIActivityIndicator to the UITableViewCell at design time(nib or storyboard) as done with the UILabel(s) and other controls.
On submitting the checkout. Change the isSending status to YES and inform the parent UIViewController to reload the table data by calling reloadData method on the UITableView.
In cellForRowAtIndexPath or willDisplay:forRowAt method set the state of the activity indicator as animating or stopped based on the isSending value. This way even if reloading the table or scrolling up and down, the activity indicator will have its state right.
Whe the submitting finishes. Change the isSending state to YES and inform your parent ViewController to reload the table by calling reloadData method on the UITableView. And since the checkin finishes in a background thread you should inform your parent ViewController using dispatch_get_main_queue. read the comments on the question you added to your question. This point you mention regarding the dispatch_get_main_queue is wrong.
I'm working on an iOS app that uses a tab bar. An item is scanned using a barcode reader, and a callback method sets the tab bar item to the result view, then sends the request to the server. The callback from the server populates the display and the result view is shown.
However, under certain conditions which depend on the response from the server, I'd like show an alternate view which allows the user to manually enter the data, and then process the data in the same way as the callback. The manual entry display can't be shown on the tab bar.
So I create a modal view and exit the callback:
EnterTextController* enterTextController = [[EnterTextController alloc]init];
presentModalViewController:enterTextController animated:YES];
return;
In the view, I take the input and call the same process called by the callback:
NSLog(#"Button Clicked!");
NSString *myText = myInput.text;
[self dismissViewControllerAnimated:NO completion:nil];
[self.mainViewController processMyText: myText];
The problem is the processMyText doesn't get executed. I have a breakpoint set and it never hits it.
I'm sure I'm not going about this correctly. Any suggestions would be welcome.
Make sure the receiver isn't nil.
This question already has answers here:
How can I wait for a NSURLConnection delegate to finish before executing the next statement?
(3 answers)
Closed 8 years ago.
I am running on Xcode 5.1. I am working on a school project where we need to load tweets in application:didFinishLaunchingWithOptions:, and after that we need to display the fetched data on a view controller.
I am using interface builder because I think it is simpler, so to answer my question please keep in mind that I am looking for solution with interface builder.
My problem is:
The tweets loading function in application:didFinishLaunchingWithOptions: in AppDelegate runs in a separate thread. I know if you are programmatically pushing the view controller in AppDelegate then you can wait for the tweets to be loaded before you initialize the view controller. But since I am using the interface builder the view controller is always initialized at start, even before the tweets loading function is finished. Therefore I am looking for a way for function in AppDelegate to notify the instance of the view controller that story board created, to reload its data once all the required tweets are downloaded.
Simply put:
How do I access the instance of any view controller that's created by the interface builder from AppDelegate? Is this a right practice?
I've googled a lot of solutions but all of them involved creating a new instance, which is different than the one that is already created at run time.
I think what you are looking for is something along the lines of the following:
You want asynchronous data loading when your application begins
You don't want the user to be able to interact with the app until there is data to display.
What I would do for this is:
Dont fetch the data in did-finish-launching
Get the instance of your viewcontroller by using the 'rootViewController` property :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
MYVIEWCONTROLLER *controller = (MY_ROOT_VIEW_CONTROLLER *)self.window.rootViewController;
[controller triggerFetch];
...
return YES;
}
in triggerFetch you would create add a UIActivityIndicator or progress bar to the main view and add a callback for the fetch function. After the fetch is complete you would remove the loading view and display the fetched content.
If your UI elements are bound to the model properly, changes to your model should reflect in the view automatically.
I'm not sure exactly what UI interface elements you are using. I'm assuming you have a UITableViewController displaying your tweets, and you are using your appDelegate as the UITVCDelegate as well to give it info on how many cells, dimensions, and the data for each cell inside its UITableView. And in the end you want it to reload data after you are done with fetching the tweets.
The simplest way would be to call [tableView reloadData] on the tableView (You can access it from the UITVC). But, that's just based on my assumptions being true about you using a UITableView to display the tweets.
Cheers!
I'm facing some weird behavior in my map based App. I'm fetching some data to display a route using some directions service. It runs in an background thread using GCD. With the data fetched I return to the main thread to update the UI :
dispatch_async(dispatch_get_main_queue(), ^{
[self.mapProvider addToExistingPolyLinePoints:coordinates withTitle:#"line" removeOldOne:NO useCurrentIndex:NO];
[_distanceLabel setText:[NSString stringWithFormat:#"%.2lf km",[self.draggingLogic getOverallDistance]]];
[self.progress setHidden:YES];
});
This all works fine in my RouteViewController. But if I go back to the RootViewController using the back button and reenter the RouteViewController and refetch the whole thing, the UI does not get evaluated. It shows the same behavior as if the UI update is not done in the main thread. The data arrives correct.
I'm wondering if it is some kind of issue regarding the view controller life-cycle of iOS, which I did not got completely. What happens when I push the back button. Obviously the ViewController is not destroyed but if I reenter it will create a new one. Is it possible from the RootViewController to determine if an instance of the target view controller is existing and perform the Segue using it?
Anyway, I'm not sure if this is regarding my issue.
Thanks for any ideas
If I understand right what you wrote, you create a new controller every time you "enter" but the dispatching block always refer to the first one you create, so the new one is displayed but the old one get the notifications...
There are lots of way to avoid this, depends on your implementation, but a simple solution may be keep a (strong) reference to the map view controller in a property of the root view controller: if it's nil (first time) you create the map controller and do all the needed stuffs, else you'll simply show it, without the creation part.
example code, in .h:
#property (strong,nonatomic) MyMapController* mapController;
in .m:
if (!self.mapController)
{
// create the controller and the update handler...
self.mapController = ... //created object
}
// show it and everything...
hope this help
You are needed to do the stuff given here....
you create a new controller every time you "enter" but the dispatching block always refer to the first one you create, so the new one is displayed but the old one get the notifications...
Ex-code, in Interface file :
#property (strong,nonatomic) MyMapProvider* mapProvider;
And in implementation file :
if (!self.mapProvider)
{
self.mapProvider = ... //create object
}
// do your stuff..
I'm trying to add a Modal ViewController to the existing application. To init and open it I use the following code
AddedViewController *addedOne = [[AddedViewController alloc] init];
[self.parent presentModalViewController:addedOne animated:YES];
If AddedViewController.xib with a View inside of course is just empty it opens nicely,
but
This throws SIGTRAP signal ((lldb) in log) at loading if AddedViewController.xib is not empty (i.e.) even if I add just a UILabel with static text there.
How can I handle this to have fully-operational ViewController (with labels, buttons, textfields, etc.. open properly?
========
UPD.
Problem easily resolved, see my answer below. =)
Assuming you are trying to present this inside the current view, you should not use self.parent and just use self.
The answer was in Use Autolayout checkbox for the ViewController settings, now everything works fine TWIMC. =))