Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
BOOK: Professional iOS Network Programming: Connecting the Enterprise to the iPhone and iPad
This is the forum to discuss the Wrox book Professional iOS Network Programming: Connecting the Enterprise to the iPhone and iPad by Jack Cox, Nathan Jones, John Szumski; ISBN: 978-1-118-36240-2
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional iOS Network Programming: Connecting the Enterprise to the iPhone and iPad section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old January 9th, 2013, 10:06 AM
Registered User
Points: 12, Level: 1
Points: 12, Level: 1 Points: 12, Level: 1 Points: 12, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jan 2013
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default Concurrent NSOperations - Chapter 6

Dear Authors,

First of all thank you for your book. I received my paperback and I find it amazing.

About Chapter 6, I see that you use concurrent NSOperations. Why?

For example, AuthenticateOperation is declared as follows:

Code:
// used to allow for asynchronous request
- (BOOL)isConcurrent {
    return YES;
}

- (void)start {
    
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(start) 
                               withObject:nil 
                            waitUntilDone:NO];
        return;
    }

    // other code here...
    
}
The start method is shunted to the main thread. I think this is due to register NSURLConnection with the main run loop. In fact, since the operation is added to the queue, the start method is executed in the thread the queue runs for us. At the same time, dealing with async APIs involve run loops to be exceuted. Am I wrong?

My question is the following: if the NSURLConnection is registered with the main thread loop, do callback functions can be invoked in a background thread? Is this thread safe?

Could you elaborate on this?

Thank you in advance.

Regards

Last edited by lrnz; January 9th, 2013 at 11:25 AM.
Reply With Quote
  #2 (permalink)  
Old January 12th, 2013, 04:45 PM
Wrox Author
Points: 61, Level: 1
Points: 61, Level: 1 Points: 61, Level: 1 Points: 61, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2012
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hey Imz - sorry for the delay and thanks for picking up a copy of the book. We're glad to hear it's been helpful!

Excellent question. In this particular example NSOperation subclassed objects are really used to organize the different units of code logically. Since we are dispatching operations via NSOperationQueue they are automatically spawned on a thread other than main (technically you don't even have to specify isConcurrent for this behavior). You are correct, the reason that the start method kicks processing to the main thread is so that the NSURLConnectionDataDelegate messages are correctly received.

Another, cleaner approach would be to do the following.

Code:
- (void)start {
    if (self.isCancelled) {
        return;
    }
    
    self.isExecuting = YES;
    
    _connection = [[NSURLConnection alloc] initWithRequest:[self request]
                                                  delegate:self];
    while(!self.isFinished) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    }
}
This runs the current runloop until the operation has completed, allowing your operation object to respond to the NSURLConnectionDataDelegate messages from the background thread. This also ensures processing of any received data is done off the main thread. To your question, with this approach you will be on a background thread so any UI updates would need to be kicked to the main thread. You could do something like this:

Code:
dispatch_async(dispatch_get_main_queue(), ^(){
	UIImage *image = [UIImage imageWithData:self.receivedData];
	if ([self.delegate conformsToProtocol:@protocol(YourProtocolName)]) {
		if ([self.delegate respondsToSelector:@selector(updateImageDelegateMethod:)]) {
			[self.delegate updateImageDelegateMethod:image];
		}
	}	
});
Thanks again Imz. I will make a note of this correction and the fact that the response handling is being done on the main thread. It should be moved to a background thread in the example.

Feel free to get in touch with any other questions. The forum is the primary place for questions but you can also contact me on Twitter @nathanhjones.
Reply With Quote
  #3 (permalink)  
Old January 13th, 2013, 07:36 AM
Registered User
Points: 12, Level: 1
Points: 12, Level: 1 Points: 12, Level: 1 Points: 12, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jan 2013
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Dear Nathan,

First of all thank you very much for your answer. I really appreciate to get in touch with book authors.

My supposition is that if concurrent NSOperations are added to a queue, the queue (by means of GCD) will create a thread for me. For non-concurrent operations this is the same. The only difference relies on the lifecycle. In the first case you have to manage it (isExecuting and isFinished are there for this). In the second, instead, the lifecycle strictly depends on main method. Am I wrong?

Obvisioulsy, concurrent operations can be excuted in your own (without a queue). In this case the programmer is responsible to write concurrent code (spawn a new thread, use async APIs, etc.).

Said this, in the meantime, I've performed some tests on my own and I've noticed that callbacks (delegates) of NSURLConnection class are called in the main thread (I verified this through [NSThread isMainThread]). The start method have been shunted to the main thread and so the NSURLConnection. In other words, all the code for managing data response (together with authentication) is managed in the main thread since the NSURLConnection has been scheduled in the main run loop.

So, my question is the following. Why using NSOperation and NSOperationQueue if then callbacks are called in the main thread? I could just create my own wrapper and set up a connection within it.

A possible advantage is that through NSOperationQueues I can order the operations and limit how many happen at the same time.

Thank you for the attention.

Regards,
Lorenzo
Reply With Quote
  #4 (permalink)  
Old January 13th, 2013, 04:09 PM
Wrox Author
Points: 61, Level: 1
Points: 61, Level: 1 Points: 61, Level: 1 Points: 61, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2012
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hey Lorenzo -

You are correct, both concurrent and non-concurrent operations will get their own threads. You are also correct in that with non-concurrent operations you simply implement the main method, whereas with concurrent operations you have a little more work to do.

Yes, in the example application the operation processing is thrown to the main thread so that the NSURLConnectionDelegate methods are received. However, the processing of the received data should have been done in the background - that's one of the corrections I noted in my last reply.

The reason we're using NSOperationQueue in this example application is to organize the different service calls logically and build a foundation for future expansion of the application. Not only will adding new service calls be pretty easy, as you noted, it handles dependency management for you.

However, the first snippet in my last note is an example of how you could use NSOperations to perform a service call without punting things over to the main thread. This allows you to leverage a bit more of NSOperationQueue without having to roll your own solution.

Hope that helps!
Nate
Reply With Quote
  #5 (permalink)  
Old January 14th, 2013, 05:05 AM
Registered User
Points: 12, Level: 1
Points: 12, Level: 1 Points: 12, Level: 1 Points: 12, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jan 2013
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hey Nate,

Thank you very much for all this.

Two last things for you. I promise. ;)

About the following quote, if callbacks are executed in the main thread, how is it possible to process data in the thread that belongs to the current operation? My intent is to process data (when I receive the *connectionDidFinishLoading* callback) to the thread the queue has created for me. How can I achieve this?

Code:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // here the response is completed, main thread is involved

    // use a thread created by the NSOperationQueue to process data, e.g. parsing data. Is there a way to retrieve it?
}
Quote:
Yes, in the example application the operation processing is thrown to the main thread so that the NSURLConnectionDelegate methods are received. However, the processing of the received data should have been done in the background - that's one of the corrections I noted in my last reply.
On the contrary, if I follow your second approach

Quote:
However, the first snippet in my last note is an example of how you could use NSOperations to perform a service call without punting things over to the main thread. This allows you to leverage a bit more of NSOperationQueue without having to roll your own solution.
do I have to stop the loop somewhere?

Code:
- (void)start {
    if (self.isCancelled) {
        return;
    }
    
    self.isExecuting = YES;
    
    _connection = [[NSURLConnection alloc] initWithRequest:[self request]
                                                  delegate:self];
    while(!self.isFinished) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
    }
}
Thank you very much for your support.

Lorenzo

Last edited by lrnz; January 14th, 2013 at 08:34 AM.
Reply With Quote
  #6 (permalink)  
Old January 14th, 2013, 11:56 PM
Wrox Author
Points: 61, Level: 1
Points: 61, Level: 1 Points: 61, Level: 1 Points: 61, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Oct 2012
Posts: 12
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hey Lorenzo -

Given your requirement I think the cleanest and simplest thing would be to use the second approach. That said, the loop will stop for you automatically when you set self.isFinished = YES. The simplest thing to do would probably be to create a few custom setters to handle setting the different states for you. Here is an example:

Code:
- (void)setIsExecuting:(BOOL)isExecuting {
    _isExecuting = isExecuting;
    if (_isExecuting == YES) {
        self.isFinished = NO;
    }
}

- (void)setIsFinished:(BOOL)isFinished {
    _isFinished = isFinished;
    if (_isFinished == YES) {
        self.isExecuting = NO;
        _connection = nil;
    }
}

- (void)setIsCancelled:(BOOL)isCancelled {
    _isCancelled = isCancelled;
    if (_isCancelled == YES) {
        self.isFinished = YES;
    }
}
With that, you would simply set self.isFinished = YES in your connectionDidFinishLoading delegate method, as well as the error delegate method (technically an error is finishing the operation and we want it cleared from the queue).

Without knowing your requirements exactly or prototyping something, if you are insistent on using the first approach you could look at maintaining a reference to the thread on which the operation was being executed prior to kicking it over to the main thread and then call back with performSelector:onThread:withObject:waitUntilDone:. There are also some GCD options but it really depends on your requirements at that point.

Hope that helps!
Nate
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
how to prevent concurrent inserting? tartuffe ASP.NET 3.5 Professionals 5 August 22nd, 2010 11:14 AM
how many concurrent queries can be run sqlserver madhusrp SQL Server 2000 0 July 7th, 2010 05:35 PM
Concurrent Caching akkad C# 2005 0 August 13th, 2006 02:05 AM
Multiple Concurrent Requests to XmlHttpRequest deepak.vasudevan Ajax 3 March 22nd, 2006 04:56 AM
Multiple Concurrent Requests to XmlHttpRequest deepak.vasudevan Javascript 0 November 14th, 2005 06:49 AM



All times are GMT -4. The time now is 09:19 AM.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.