NSOperationQueue callback before an operation is started? - objective-c

Is there a way I can find out if/when an operation is about to start/execute on an NSOperationQueue?
I am using NSURLConnection's setDelegateQueue: and I need to know when it fires.

In your NSOperation subclass add a copy property for a willStartBlock. At the beginning of main - before any other actions - call this block if it is set.
This way you can set up the actions to perform when the operation starts at the same time when you create the operation and before you put it into the operation queue.
The problem in your specific question is that you don't create the operations that are created on your queue. You can try to subclass NSOperationQueue and override the three public addOperation* methods. If you're lucky then one of these is the one that the NSURLConnection uses to append the callback operation to your queue.

May i know what exactly you want to do.
I am not sure what you want to achieve as it is not clear from your question but you can do something like that:
currentConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
if (self.operationQueue) {
[currentConnection setDelegateQueue:self.operationQueue];
}
[currentConnection start];
NSURLConnection gets invoked once start method gets called.
You can also subclass NSOperation and override start method.

Related

executing NSOperations in another NSOperation

I have an app that needs to synchronize multiple entity types with a backend using an API.
To do that I created a subclass of NSOperation for each HTTP method (GET/POST/PUT/DELETE => 4 operations). For a given entity these operations have to be run in a specific order, so I created a 5th operation subclass which contains the synchronization sequence (basically an operation that creates multiple GET/POST/PUT/DELETE operations in the appropriate order and adds these operations to a queue created by the operation.).
Since i want to be able to synchronize multiple kind of entities (for example 'Users' / 'Events' / 'Tasks') at the same time depending on the connection of the user and with dependencies between some types of entities (for example i need to finish the 'Users' synchronization before i can start concurrently the 'Events' and 'Tasks' synchronizations) I use a NSOperationQueue that contains only NSOperations of type synchronization.
So just to sum up, if I made 1 change of each type (1 create, 1 update, ...) on each type of object, and that i want to synchronize everything. I'll have 1 NSOperationQueue that will contain 3 NSOperations (1 for each type of object), and each NSOperation will have its own NSOperationQueue that should run 4 NSOperation (1 for each change type).
Now comes the problems :
1st/ The "sub-operations" are using async NSURLConnection, and I don't know how should the NSURLConnection be configured ?
Should i use something like this :
connection = [[NSURLConnection alloc] initWithRequest: theRequest delegate: self startImmediately: NO];
NSRunLoop * currentRunLoop = [NSRunLoop currentRunLoop];
[currentRunLoop addPort: [NSPort port] forMode: NSDefaultRunLoopMode];
[connection scheduleInRunLoop: currentRunLoop forMode: NSDefaultRunLoopMode];
[connection start];
[currentRunLoop run];
Or should i use that :
while (!finished)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
2nd/ At the moment i am overriding start for the operations because i want to be able to start them without using an NSOperationQueue when I have only 1 operation. Is it correct ? If yes, are there examples somewhere of start method implementations ?
3nd/ About the runloops and threads, each operation will always get a different runloop and thread ? And this thread / runloop management must be handled in the start method if i override it ?
4th/ is it a problem to use queue like I do (i think it's justified in my case) ?
1) I tend to use the synchronous request when running in the background. I find it's cleaner and you're in the background already anyways.
2) Subclassing NSOperation in my opinion is not flexible and creates sort of sloppy code. Instead I would suggest keeping some sort of services class that has an NSOperationQueue and from there use the [NSOperationQueue addOperationWithBlock:]. You can even take it a step further if you want and create an NSBlockOperation. The main thing you gain from this API is the ability to have a completion block. But i find that keeping the services layer and the operations (in this case in the form of blocks) easier to manage and understand. You can even create functions that return blocks so the blocks can be reused how ever you need. This may help you to have better code reuse than subclassing NSOperation
Example:
-(void)foo
{
__weak ClassName wself = self;
void(^opBlock)() = ^{ [wself doStuff]; };
[_queue addOperationWithBlock:opBlock]
}
3) Yes your queue will have its own run loop.
4) Maybe refer to the others

how to run functions in order in objective c

i have a problem with queued functions. i want to run my function and when my first function finishes running, i want to start other one.
-(void)firstFunct
{
// sending and getting information from server.
// doing sth and creating data to use in my second function.
}
and my second function is:
-(void)secondFunct
{
// using data coming from first function
}
i am now using these 2 functions in like that
-(void)ThirdFunct
{
[self firstFunct];
[self performSelector:#selector(secondFunct) withObject:nil afterDelay:0.5];
}
but there is a problem that this method is not good to use. i want to learn if there is an efficient way to run the functions one after the other.
You can simply call one function after the other:
- (void) thirdFunct
{
[self firstFunct];
[self secondFunct];
}
If you want to run this whole block in the background, not blocking the UI thread, use Grand Central Dispatch:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, 0), ^{
[self firstFunct];
[self secondFunct];
});
And if the first function contains some asynchronous call, that call should offer some kind of interface to run code after the call finishes, like a delegate call or a completion block.
Well, yes, zoul's spot on for the normal case.
However, you mentioned a server was involved. In that case, you probably have an asynchronous request. What you want to do is read the documentation of the class you use to make the network request, and learn what callbacks it uses to notify you when it is complete.
Cocoa offers nice concurrency management classes like NSOperation and NSOperationQueue. You could use them to simplify the logic behind chaining your asynchronous calls without creating explicit connections in code to call method 3 after work 2 completes, and method 2 after work 1 completes, and so on. Using dependency management, you could easily specify those dependencies between your operations.
Here's a simple example of how you would use that code. Suppose you are downloading some data asynchronously in all those three methods, and you've created a NSOperation subclass called DownloadOperation.
First, create a NSOperationQueue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
Then, create the three download operations.
DownloadOperation *a = [[DownloadOperation alloc] init];
DownloadOperation *b = [[DownloadOperation alloc] init];
DownloadOperation *c = [[DownloadOperation alloc] init];
Then, specify the dependencies between your operations. Dependencies simply say that an operation can run only if all the operations it depends upon are complete. In your example, the dependencies look like c <- b <- a, which can be broken down into two steps:
[b addDependency:a];
[c addDependency:b];
Now add these operations to the queue.
[queue addOperations:#[ a, b, c ] waitUntilFinished:NO];
The queue will automatically start processing all operations at this point, but since we've creating this chaining sort of a dependency, they will be executed one after the other in our particular example.
I've created a sample project on github demonstrating it with a simple example at https://github.com/AnuragMishra/ChainedOperationQueue. It fakes an asynchronous operation by creating a timer, and when the timer finishes, the operation is marked complete. It's written using Xcode 4.5, so let me know if you have issues compiling it in older versions.
if you write your methode like this
-
(void)ThirdFunct
{
[self firstFunct];
[self secondFunct];
}
secondFunct is called after firstFunct. Your problem comes certainly from the network request which is asynchronous. To be sure that your secondFunct is executed after an asynchronous request you have to execute it from delegate or block.
Checkout NSURLConnectionDelegate if you NSURLConnection

Objective-C wait for asynchronous HTTP-Request to finish

I use the following code to execute a HTTP-Request:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
After that I want to use the received data. My problem is that i can't do this in connectionDidFinishLoading, but have to do this on another position in my code. As this is an asynchronous task, how can I verify that I don't start to use the received data before the task is completely done?
Thanks in advance,
Edit: My main problem is that the delegates are called after the code which uses the received data.
you just have to keep the received data in an ivar an use it whenever you want. if you really want to be sure, you can also use a BOOL set to YES in
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
don't forget that since iOS 5, the NSURLConnectionDelegate (and DownloadDelegate) have changed.
Download the AFNetworking library and use it for your connections. It has blocks methods, which (to me) are much 'cleaner' to use instead of delegate methods. AFNetworking is available on iOS 4 and higher.
https://github.com/AFNetworking/AFNetworking
Read this post on some basics of AFNetworking:
http://engineering.gowalla.com/2011/10/24/afnetworking/

NSURLConnection returning zero length data

I had async NSURLConnections working just fine when I was using my viewController as the delegate, have all sorts of connections now and I want to do them all through a singleton Connection object. So I'm having Connection create a new delegate object for each connection it makes. Connection is instantiated in the app delegate, but the +(void)send:(Message *) function probably terminates.
My feeling about how this works is that the delegate listeners get put in the run loop (I'm not totally clear on this but I think they're not in separate threads. Shouldn't matter because the delegates allocate their own responseData memory.) and the connectionDidFinishLoading executes just fine, but with an empty responseData. By that I mean I find myself in connectionDidFinishLoading but responseData has zero bytes.
Code creating the app delegate (in the send method) is:
ConnectionDelegate *delegate = [[ConnectionDelegate alloc] init];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:request delegate:delegate];
So my question is two folded:
Is the problem that the send method terminates? The delegate pointer has local scope.
If that's the problem, what can I do to keep the delegate alive?
You should double check your delegate's implementation of connection:didReceiveData:
Remember that you are responsible for collecting the incoming data segments there.
Please read Apple's doc(, especially URL loading system programming guide) and sample code again if any doubt.

How can I consolidate deferred/delayed calls in Objective-C?

I'd like to ensure that certain maintenance tasks are executed "eventually". For example, after I detect that some resources might no longer be used in a cache, I might call:
[self performSelector:#selector(cleanupCache) withObject:nil afterDelay:0.5];
However, there might be numerous places where I detect this, and I don't want to be calling cleanupCache continuously. I'd like to consolidate multiple calls to cleanupCache so that we only periodically get ONE call to cleanupCache.
Here's what I've come up with do to this-- is this the best way?
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(cleanupCache) object:nil];
[self performSelector:#selector(cleanupCache) withObject:nil afterDelay:0.5];
There's no real built-in support for what you want. If this is common in your program, I would create a trampoline class that keeps track of whether it's already scheduled to send a message to a given object. It shouldn't take more than 20 or so lines of code.
Rather than canceling the pending request, how about just keeping track? Set a flag when you schedule the request, and clear it when the cleanup runs.