Avoid multiple web service call in ios - ios

I am inserting data to server database from my app.
on submit button I am calling inserdata web services.
My data inserted in database. but I have one problem,
before I get first result back when I tap on submit button again then same record inserted multiple times in database.
Please help how can I avoid this. (also by mistake I have tapped multiple times on submit button then same record inserted multiple time).

when web service triggers first time.... set button.selected = yes and in function check if button isSelected then not perform action. Use this bool value to distinguish between both conditions.

When user pressed submit button, show progress hud or an activity Indicator View (loading overlay). This will let user know that some processing is going on and make them not trigger any other action.
Also set synchronous property to that object from which you are calling this WebService. (When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.)
And when you got response, clear all data from your form or your app. Because If data is cleared, then user can't insert same record into Database.
So, No need to disable that submit button.

Try this.
- (IBAction)doneCollectionSaveAction:(id)sender {
if([activity isAnimating]==YES){
[ALToastView toastInView:[UIApplication sharedApplication].keyWindow withText:#"Please wait..."];
}else{
[self addToCollection];
}
}
or
- (IBAction)doneCollectionSaveAction:(UIButton *)sender {
if (sender.selected==YES) {
//do nothing
[ALToastView toastInView:[UIApplication sharedApplication].keyWindow withText:#"Please wait..."];
}else{
//send data to server
self.buttonDoneOutlet.selected=YES;
[self addToCollection];
}
}
//and self.buttonDoneOutlet.selected=NO; //failure network call

Related

How to implement a search queue

I am new in swift3.0 I am implementing a custom search box. I wish to know how can i make a search queue such that on text change in searchbox i need to perform search operation with new text and if there is an existing search operation going on cancel that. I also want to include threshold ontextchanged. So that search operation does not get fired very frequently
Your question is somehow general, but let me tell you how I accomplished this in Swift 3 and AFNetworking (this assumes you wish to search for the data on the server).
I hold a reference of the networking manager in the properties of the view controller:
//The network requests manager. Stored here because this view controller extensively uses AFNetworking to perform live search updates when the input box changes.
var manager = AFHTTPRequestOperationManager()
Afterwards, using UISearchController I check to see if there is any text entered in the search box at all and, if it is, I want to make sure there aren't any other ongoing AFNetworking tasks from now by closing any of them which are still running:
//Called when the something is typed in the search bar.
func updateSearchResults (for searchController: UISearchController) {
if !SCString.isStringValid(searchController.searchBar.text) {
searchController.searchResultsController?.view.isHidden = false
tableView.reloadData()
return
}
data.searchText = searchController.searchBar.text!
/**
Highly important racing issue solution. We cancel any current request going on because we don't want to have the list updated after some time, when we already started another request for a new text. Example:
- Request 1 started at 12:00:01
- We clear the containers because Request 2 has to start
- Request 2 started at 12:00:02
- Request 1 finished at 12:00:04. We update the containers because data arrived
- Request 2 finished at 12:00:05. We update the containers because data arrived
- Now we have data from both 1 and 2, something really not desired.
*/
manager.session.getTasksWithCompletionHandler { (dataTasks, uploadTasks, downloadTasks) in
dataTasks.forEach { $0.cancel() }
}
/**
Reloads the list view because we have to remove the last search results.
*/
reloadListView()
}
In the end, I also check in the failure closure if the code of the error is not NSURLErrorCancelled. Because, if that happened, I don't display any error message or toast.
//The operation might be cancelled by us on purpose. In this case, we don't want to interfere with the ongoing logic flow.
if (operation?.error as! NSError).code == NSURLErrorCancelled {
return
}
self.retrieveResultListFailureNetwork()
Hope it helps!

how to know when asynchronous search using MapKit is complete

I am using mapkit to allow a user to search for an address. Pressing another button (the goButton) will ask them to confirm a formatted address populated using the results of their search, and also will send a command to search behind the scenes if the user entered text but did not actually search for the address before selecting goButton. My problem is that because the search is completing asynchronously, the confirmation function is being called too soon.
Is there a way I can tell when the search is completed? I tried putting a bool at the end of searchBarSearchButtonClicked and a while loop before calling confirmHostAddress that checked the value of the bool, but it did not detect a change. Thanks for your help.
#IBAction func goButton(sender: UIButton) {
//check and see if there is an address, if not, do search behind the scenes
if (myAddress == nil)
{
if (mapSearch.text != "")
{
self.searchBarSearchButtonClicked(self.mapSearch)
confirmHostAddress()
}
else
{
alertTextNeeded()
}
}
else
{
confirmHostAddress()
}
}
It looks like your async search is in confirmHostAddress()? That function needs to have a callback block, which will (hopefully) be running on a background thread. Within that callback, use dispatch_async() to enqueue, onto the main queue, the UI change that you want.
Search button click (on main queue) triggers search (on background queue), and search completion triggers (on main queue) UI update.

UI Slow to Update *ONLY* If Called In Response To Change Occurring in NSURLSessionUploadTask Completion Block

The app interacts with php scripts on my server. A user can create a booking, and details are written to a database. Subsequently, they can cancel that booking.
Within the app, a booking is an object, responsible for gathering its own details from the server. A booking can also cancel itself (at the user's request) - pressing "the cancel button" in BookingViewController calls the booking's (void)cancelBooking method, which posts to bookings-cancel.php using an NSURLSessionUploadTask with json data rolled from #{ #"invoiceNumber": self.invoiceNumber }.
The database is updated, the uploadSession returns new details, and the booking updates itself according. All of this is nicely responsive - up and back in less than a second, consistently.
The problem comes when I attempt to update the UI on BookingViewController (labels for delivery date and price) using values read from the booking object after it has updated itself (within the uploadSession completion block).
BookingViewController is assigned as the booking's delegate. The booking is setup for KVO on its own "price" property. Whenever the price changes, the booking calls a delegate method priceDidChange:(NSString *)updatedPrice on BookingViewController, triggering an NSLog and updates to deliveryLabel.text and priceLabel.text.
- (void)priceDidUpdate:(NSString *)updatedPrice {
NSLog(#"priceDidUpdate delegate notification - updatedPrice is: %#", updatedPrice);
[self.deliveryLabel setText:#"N/A"];
[self.priceLabel setText:updatedPrice];
}
Testing has shown that if I update the price directly from the "cancel" button, or with any other explicit command (e.g., self.price = #"123.45") within the cancelBooking method outside of the uploadTask, then the UI updates just as quickly as the NSLog is written out (i.e., near instantaneously).
However, if the price is updated within the uploadTask completion block, the NSLog will write out just as responsively but the updates to deliveryLabel.text and priceLabel.text are very slow to occur - the delay varies between 5 and 12 seconds, approximately.
I've got NSLogs all over the place, and am confident this is not merely about a delay getting the updated value to or from the booking object. Easily twenty times already I have seen "priceDidUpdate delegate notification - updatedPrice is: 0.00" (the updated price), then counted to 10 before self.priceLabel.text is actually set to #"0.00". Totally stumped.
In case it matters, the NSURLSession is configured using ephemeralSessionConfiguration with no adjustments.
Is there any reason why the UI updates in BookingViewController should take longer to occur based on whether or not the call to priceDidChange comes from inside or outside the uploadTask completion block?
Thanks in advance!
Use main queue to update the UI. Use following code:
- (void)priceDidUpdate:(NSString *)updatedPrice
{
dispatch_async(dispatch_get_main_queue(), ^()
{
//Add method, task you want perform on mainQueue
//Control UIView, IBOutlet all here
NSLog(#"priceDidUpdate delegate notification - updatedPrice is: %#", updatedPrice);
[self.deliveryLabel setText:#"N/A"];
[self.priceLabel setText:updatedPrice];
});
}

Truncate all with MagicalRecord not saving after app closes

I'm using Magical Record, and what I want to do is when the user enters a multi item selector table view, he can check and uncheck many items, which, when done is pressed, are saved.
When I'm using the app there are no issue, but when I'm leaving and going back, all items that were checked before and the new ones are checked (let's say I checked 5 items at launch, then I go back in the multi item selector, uncheck them and check 5 others, the 10 will be checked when I'm going back in multi item selector after leaving the app).
Here is my code when pressing the "Done" button of my selector:
-(void)selector:(KNMultiItemSelector *)selector didFinishSelectionWithItems:(NSArray *)selectedItems
{
[self dismissViewControllerAnimated:YES completion:^{
currentFriends = selectedItems;
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
[FriendsSelected MR_truncateAll];
for (KNSelectorItem * user in selectedItems) {
FriendsSelected *friend = [FriendsSelected MR_createEntityInContext:localContext];
friend.friendID = user.selectValue;
friend.friendName = user.displayValue;
NSLog(#"Friend %# Saved", friend.friendName);
}
}];
}];
}
I tried saving when app terminate, I tried using completion and background tasks, nothing seams to work. Maybe I'm missing something ?
PS: I tried this other answer but it's not working, and MR_save is deprecated in the version I use.
Use MR_truncateAllInContext: to make sure your data is deleted using the context that is used for the actual save operation you're initiating with saveWithBlock:

how to response before the server return on iOS

my situation is like this:
when you press a button, it will first hide the button, and then send a http request to the server, the request is sent to a php script and execute an "exe" to use the printer to print something.
But when I test the app, I find the button hides when the "exe" on the server exits, the result is that when I press the button, the application is like "not response", the button
dose not hide and keep the state of "press down", it is not user-friendly. So any ideas
to help me solve this ?
Finally, I used slef performSelectorInBackground, since I did not care the result php return, it works well and easier than Asynchronous call.
It may be that you are making a synchronous call to the server. Check here for how to make asynchronous calls.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
interface updates are only done after the method finishes. try running the php part in an extra method with performSelector:
- (void)yourCurrentMethod {
button.hidden = YES;
[self performSelector:#selector(doSomething)];
}
- (void)doSomething {
/* call php script, etc */
}
Sorry, what I meant was performSelector:withObject:afterDelay:
- (void)yourCurrentMethod {
button.hidden = YES;
[self performSelector:#selector(doSomething) withObject:nil afterDelay:0.1];
}
- (void)doSomething {
/* call php script, etc */
}
That will process the hidden in the UI and then call the doSomething-method without making it a background thread, so you can use a synchronous request. Using asynchronous requests is a little more work (but cleaner), which you don't really need, if you only want to call the php and don't care about the result.

Resources