What to do when users generate the same action several time waiting for download? - objective-c

I am designing an IPhone application. User search something. We grab data from the net. Then we update the table.
THe pseudocode would be
[DoThisAtbackground ^{
LoadData ();
[DoThisAtForeground ^{
UpdateTableAndView();
}];
}];
What about if before the first search is done the user search something else.
What's the industry standard way to solve the issue?
Keep track which thread is still running and only update the table
when ALL threads have finished?
Update the view every time a thread finish?
How exactly we do this?

I suggest you take a look at the iOS Human Interface Guidelines. Apple thinks it's pretty important all application behave in about the same way, so they've written an extensive document about these kind of issues.
In the guidelines there are two things that are relevant to your question:
Make Search Quick and Rewarding: "When possible, also filter remote data while users type. Although filtering users' typing can result in a better search experience, be sure to inform them and give them an opportunity to opt out if the response time is likely to delay the results by more than a second or two."
Feedback: "Feedback acknowledges people’s actions and assures them that processing is occurring. People expect immediate feedback when they operate a control, and they appreciate status updates during lengthy operations."
Although there is of course a lot of nonsense in these guidelines, I think the above points are actually a good idea to follow. As a user, I expect something to happen when searching, and when you update the view every time a thread is finished, the user will see the fastest response. Yes, it might be results the user doesn't want, but something is happening! For example, take the Safari web browser in iOS: Google autocomplete displays results even when you're typing, and not just when you've finished entering your search query.
So I think it's best to go with your second option.

If you're performing the REST request for data to your remote server you can always cancel the request and start the new one without updating the table, which is a way to go. Requests that have the time to finish will update UI and the others won't. For example use ASIHTTPRequest
- (void)serverPerformDataRequestWithQuery:(NSString *)query andDelegate:(__weak id <ServerDelegate)delegate {
[currentRequest setFailedBlock:nil];
[currentRequest cancel];
currentRequest = [[ASIHTTPRequest alloc] initWithURL:kHOST];
[currentRequest startAsynchronous];
}
Let me know if you need an answer for the local SQLite databases too as it is much more complicated.

You could use NSOperationQueue to cancel all pending operations, but it still would not cancel the existing operation. You would still have to implement something to cancel the existing operation... which also works to early-abort the operations in the queue.
I usually prefer straight GCD, unless there are other benefits in my use cases that are a better fit for NSOperationQueue.
Also, if your loading has an external cancel mechanism, you want to cancel any pending I/O operations.
If the operations are independent, consider a concurrent queue, as it will allow the newer request to execute simultaneously as the other(s) are being canceled.
Also, if they are all I/O, consider if you can use dispatch_io instead of blocking a thread. As Monk would say, "You'll thank me later."
Consider something like this:
- (void)userRequestedNewSearch:(SearchInfo*)searchInfo {
// Assign this operation a new token, that uniquely identifies this operation.
uint32_t token = [self nextOperationToken];
// If your "loading" API has an external abort mechanism, you want to keep
// track of the in-flight I/O so any existing I/O operations can be canceled
// before dispatching new work.
dispatch_async(myQueue, ^{
// Try to load your data in small pieces, so you can exit as early as
// possible. If you have to do a monolithic load, that's OK, but this
// block will not exit until that stops.
while (! loadIsComplete) {
if ([self currentToken] != token) return;
// Load some data, set loadIsComplete when loading completes
}
dispatch_async(dispatch_get_main_queue(), ^{
// One last check before updating the UI...
if ([self currentToken] != token) return;
// Do your UI update operations
});
});
}
It will early-abort any operation that is not the last one submitted. If you used NSOperationQueue you could call cancelAllOperations but you would still need a similar mechanism to early-abort the one that is currently executing.

Related

How to properly execute performFetchWithCompletionHandler with multiple blocks inside

I'm using the background fetch method performFetchWithCompletionHandler in order to update some user data. However, those processes are fairly complicated and include block statements, so they don't execute synchronously.
My concern is that I am always returning completionHandler(UIBackgroundFetchResultNewData);
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Start background data fetch");
// Update data -- this method contains various blocks inside
[GETDataRequest updateUserDataWithUser: user];
// Update images -- this method contains various blocks inside
[GETImagesRequest updateUserImagesWithUser: user];
NSLog(#"Background Data Fetch completed");
completionHandler(UIBackgroundFetchResultNewData);
}
According to this post, in regards to completionHandler(UIBackgroundFetchResultNewData) the following was mentioned:
You have to call this to let iOS know what the result of your background fetch was. It uses this information to schedule future background fetches. If you neglect to do this, future background fetches may be delayed by the OS. The consequences of not calling this handler might include terminating your app altogether.
As you can see here, I am always saying it's successful whether or not it actually is. The answerer had this to say about my situation:
...you should call the completion handler only when your fetch is actually complete. Otherwise iOS will probably put your application back to sleep before the connection completes, and apps shouldn't actually be able to determine UIBackgroundFetchResultNewData versus UIBackgroundFetchResultNoData or UIBackgroundFetchResultFailed until then anyway. How do you know your connection will succeed?
Is what I'm doing ACTUALLY a problem? Will it actually cut off the updates? If it is going to produce unexpected results, what's the solution to this mess? The answer to the question I mentioned wasn't clear enough to me. I have tried using block variables to make it function as it should, but have been unsuccessful. Much appreciated.
The code you are using is meant for Background Fetch Refresh functionality, through this you can make a quick refresh to your app when its in background by mentioning the system time interval to minimum. This service is available in the delegate method performFetchWithCompletionHandler and it will last for 30 seconds. You need to manage your code accordingly to get updated result and then at end as per your result you need to call the appropriate completion handler block.
If you have the long running background task I will prefer then to use Background Fetch Services using NSURLSessions.

Best way to wait for multiple getObjectsAtPath to finish

When my user logs in, I have multiple:
[[RKObjectManager sharedManager]
getObjectsAtPath:path
parameters:nil<br/> success:
^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
Now, I want to wait for all of them to finish to show the next page. I thought about putting them one inside another and return from the block until it reaches the last one, but this seems to kill the purpose of having async calls.
I thought about having a dictionary where I set the keys to YES and NO once a specific part is done, and wait for all the keys to be set to YES, but this seems prone to locks/concurrency problems.
So, any ideas to do this?!
Thanks!
The dictionary route should work and shouldn't have any threading issues as the success & error callbacks are all run on the main thread.
Alternatively you could use a simple counter if you don't care about which ones are finished and which aren't.
Alternatively you could use the operationQueue of the RKObjectManager and check in each success block if any tasks are still to be completed (though you need to consider the effectiveness if you are using the sharedManager and how many other things may be on the queue at the same time).

iOS - wait till a process ends

This is an IOS6 question.
I have an app that is calling a class (A) to check something. Then I want to call a class (B) to do something else
Is it possible to make sure process B doesn't start before process A finishes?
At the moment, I just call one after the other in the RootVC.
Each is showing a modal view, and I only get to see B ..
[self performA];
[self performB];
Thanks
There are several tools for managing the order of execution of parts of your application available to you. However since you are presenting view controllers you have a couple of constraints; you don't want to block the main thread (or else the app will become unresponsive) and you must perform UI actions on the main thread.
In this case the most common, and probably most appropriate, solution is to setup a callback to trigger action B when action A finishes.
The modal view controller presented as part of A might call a delegate when it has finished its task successfully. That delegate can then begin task B.
Alternately you might pass a block to A which A will execute when it finishes. That block can then perform task B.
I took the dare and failed.
The story: My app has been giving me hell updating from an iOS4 target to iOS6 (with a contingent sub of code for iOS5/3GS). It crashes unless i use #try etc... with a built in delay interval on the reattempt (which is stupid, 'cause I don't know how large a database the users have, nor how long it will take to load them). It's a painful way to get around my real problem: the view loads before the CoreData stack (logs) can be loaded completely and I don't see a way to make the initial view wait until its NSMutableArray (based on the CoreData database of my object) loads. Basically, I keep getting a false error about addObjectsSortedBy: the foremost attribute of my entity.
Threading does seem to be the answer, but I need to load an NSMutableArray and feed it into my initialViewController, which will be visible on every launch (excluding FirstTime initial), but my attempt (okay, 12 attempts) to use threading just made the crash occur earlier in the app launch.
The result: I bow down to those who have wrangled that bull of threads.
My solution has been to build in a notification in the AppDelegate.m, my initialViewController viewDidLoad is told to listen for it before anything else. If it gets the notification it skips ahead and completes the normal process unto [super viewDidLoad]; if not, it executes #try, #catch, #finally. In the #try I attempt to proceed as though the notification arrived (like it was a little late), then I handle (#catch) the error by displaying a "Please Wait" label to the user, then I tell the app to wait .xx and repeat the original addObjectsSortedBy: command as though everything were kösher to begin with.The sweet-spot for my app, with images and data in the logs appears to be .15 for the wait interval #50 test entries, with time to spare and no obvious lag on load. I could probably go down to .10 #50 entries.
BUT: I don't know how to scale this, without having the logs loaded enough to get an object.count! Without that, there is no way to scale my delay, which means it may (read:will) not work for large logs with many entries (200+)!
I have a work-around, but I'm going to keep trying to get a grip on threading, in order to have a solution. And to be honest, once I hit 20 entries, the notification never hits in time for the #try to occur.
If you can, use threads. I painted myself into a corner by failing to do so early on and am paying for it: my app has been in need of an overhaul, but I need this notch in my belt before it will be worthwhile. The earlier you can implement threaded loading the better for your long-term development. In the meantime, you may be able to use my work-around to continue testing other parts of your app.

multiple writes on a writestream in node.js

I've been looking at the code of node-dirty and noticed that when writing a lot of data to a file, the original programmer has chosen to bunch the writes into several groups and issue writes of the groups one at a time, but they are all issued simultaneously as part of one loop, without waiting for any callbacks. I have three questions about this. I have a similar problem to solve.
Is this more efficient in some way? Should I be bundling writes too?
How should I choose the optimum bundle size? Why not just write one group?
If I sign up to the on('drain') event on the writestream, will it be emitted only once after all the simultaneously issued writes have completed? Or after each? (my guess is the former)
If the on('error') is emitted, will the ('drain') event also be emitted? Or are they mutually exclusive?
thanks
Is this more efficient in some way?
Should I be bundling writes too?
It's inefficient to make many small writes. sending a write command has overhead attached to it. So writing just 5 bytes instead of a 1000 is more expensive.
How should I choose the optimum bundle
size? Why not just write one group?
Optimum size sounds like a black art to me. I presume there are good reasons for not making it one big write. Probably to start writing earlier then later. It's slightly more efficient to start a bit earlier.
If I sign up to the on('drain') event
on the writestream, will it be emitted
only once after all the simultaneously
issued writes have completed? Or after
each? (my guess is the former)
Drain triggers when everything in the write queue has finished writing. So as long as you append to the write queue faster then it writes it, it should only trigger once. You'd need one hell of a system to pull of an edge-case like that.
If the on('error') is emitted, will
the ('drain') event also be emitted?
Or are they mutually exclusive?
Even if it is emitted it doesn't make sense to do error handling in 'drain'. If an error has occurred I would always assume that the entire writing operation has failed and not try to recover mid-write.
For 4. If the on('error') is emitted, will the ('drain') event also be emitted? Or are they mutually exclusive?
You are worried about it since you don't want to maintain state in your application right. So, maybe you could use a convenience function:
function not_if(proc, veto_inner) {
var vetoed = false;
return {
proc: function() {
if (!vetoed) { return proc.apply(null, arguments); }
},
vetoer: function() {
if (!vetoed) {
vetoed = true;
veto_inner.apply(null, arguments);
}
};
}
Now, you can set the 'error' handler to vetoer and the 'drain' handler to 'proc' and not wirry about 'drain' being called after 'error' is called.

problem with asynchronous programming while calling 2 methods in Objective-C

Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = [classB_Obj authenticateMobileUser];
}
Inside ClassB:
-(AuthenticateObj*)authenticateMobileUser
{
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
return authenticate_G_Obj;
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
}
Now once the authenticateMobileUser method of classB returns the controll back to ClassA, we will get the Object authenticate_Obj initiated.
My problem is , when i run the project the authenticate_Obj is NULL... actually when it enters the handler method , the Object is initiallized. but the controlled is returned back to ClassA, without entering into Handler method. I guess this is the problem of Asynchronous execution.
How to make it enter into handler method and then only return the controll to ClassA??
Plz help me..
Thank You.
It sounds like what you think you want to do is to block execution until authentication completes. This might be possible if AuthenticateMobileServer spawns a background thread to work in -- you'd use a synchronisation object such as NSLock -- but it's really a Bad Idea. Why have a background thread at all if you're going to block anyway? And thread synchronisation is notoriously tricky and prone to errors if you don't know what you're doing, which (let's face it) you don't.
Instead, you probably should accept that there will be a period of uncertainty while the authentication takes place, during which your app should keep processing in some intermediate state, and then use a callback to notify you when the authentication is complete and you can then go on with whatever it is you need to do with the authenticated user.
There are a bunch of ways you could do this, and there's not enough detail in the question to say exactly which would be best. But you already seem to be using something very similar within ClassB, so I'd say do the same from ClassA:
Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = nil;
[classB_Obj authenticateMobileUserAndNotify:self action:#selector(authenticatedObject:)];
// returns more or less immediately, not yet authenticated
}
-(void)authenticatedObject:(YourAuthObjectClass*) authObj
{
authenticate_Obj = authObj;
// do post-authentication stuff here
}
Inside ClassB:
-(void)authenticateMobileUserAndNotify:(id)target action:(SEL)sel
{
// I'm making these ivars for simplicity, there might be other considerations though
callbackTarget = target;
callbackSelector = sel;
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
[callbackTarget performSelectorOnMainThread:callbackSelector withObject:authenticate_G_Obj waitUntilDone:NO];
}
Obviously this is just a sketch and not intended to be used as is. And you'll need to consider what goes on in your app while in the waiting state, with authentication in progress but authenticate_Obj still nil. But hopefully you get the idea.
I think you are saying that AuthenticateMobileServer:action: is asynchronous and you want to block until it's finished so you can get the return value. Unfortunately, we can't really tell you without knowing how it works. The main question is does it run the Handler action on the main thread or a secondary thread.
If it runs the action on the main thread, the best strategy is to return immediately from authenticateMobileUser without waiting for the authentication object and disable the UI elements that depend on being authenticated. Then later when you get the authentication object, you should re-enable the UI elements.
If it runs the action on a background thread, the easiest thing is to set up another method similar to Handler (by the way, the naming convention for methods and variables is to start with lower case), which you then invoke from Handler with performSelectorOnMainThread:waitUntilDone:. You can then use the same strategy as outlined above.
Both answers of JeremyP and walkytalky are correct and go at the heart of creating a respondsive UI. The rule of thumb:
If you doing potentially blocking operations such as networking on the main thread, you will get in trouble.
There are at least two reasons:
you are blocking the run loop so it cannot process user events anymore. This will result in a spinning beachball on the mac and a unresponsive UI on both mac and iOS.
If you are on iOS, there is a watchdog going around and checking if your UI is still responding to user events. If you are blocking the UI longer than I think 20s you will be terminated with the error code 0x8badf00d.
So to get this things done which maybe take some time you have to do it on the background thread. As the two answers of JeremyP and walkytalky point out often you get a callback. That is fine but there are in total three ways of messaging:
Delegation
Notifications
Kev-value-observing
All three can be and are used. There are subtle differences between them. One of the most important is that delegation is a 1:1 messaging whereas the other to are a 1:n messaging.
Now that said do not think that you have to use NSThread. Have a look at NSOperation and NSOperationQueue instead. They allow to encapsulate pieces of work in an operation and let them run on a queue in the background. Also if you are using these callbacks with the #selector(methodname:) syntax there is something new: blocks. Often there are equivalent methods which take a block instead of a selector to be executed as a callback.
To finish here is the golden rule:
You may update your model on the background thread, but NEVER update your UI on a background thread.
Check out the WWDC10 videos about these topics. There is a great 2-part talk about networking which explains the concepts in detail.