RunLoops and delegates

3 views
Skip to first unread message

iPhoneCode

unread,
Feb 18, 2009, 1:43:01 PM2/18/09
to ObjectiveResource
Hi folks,

I have started using OR in my project and now I realize that currently
the framework sets up its own ConnectionDelegate and forces it to be
managed in the current thread's run loop. The effect is that the UI
gets unresponsive until the thread is awaken.
How have you guys designed the framework to work regarding
asynchronous calls? Should clients start their own separated thread?
The example app provided does not show it at least.

thanks
Rodrigo

iPhoneCode

unread,
Feb 18, 2009, 3:16:37 PM2/18/09
to ObjectiveResource
The current approach results in getting sometimes this log:

UnlockAndDrawWindows: failed to draw after waiting 10 seconds. main
run loop mode: com.yfactorial.objectiveresource.connectionLoop
If you were not using the touch screen for this entire interval (which
can prolong this wait), please file a bug.

Mathias Meyer

unread,
Feb 18, 2009, 4:18:05 PM2/18/09
to objectiv...@googlegroups.com

Having done something similar to OR in RubyCocoa myself I can say that
it's safer for OR to expect the user to run the code in a separate
thread. It makes more sense to me than trying it the other way.

I played around with different approaches to handle this, since it was
of course the first thing that you come across when dealing with
network requests. I used both a normal thread (NSThread) and an
NSLoadOperationQueue to handle the network tasks in the background.
You have to do more work to ensure that you're always updating the GUI
from the main thread, when you're handling events from the queue or
the thread, but that's what performSelectorOnMainThread is for.

Cheers, Mathias
--
http://paperplanes.de
http://twitter.com/roidrage

Josh Vickery

unread,
Feb 18, 2009, 5:39:55 PM2/18/09
to objectiv...@googlegroups.com
> Having done something similar to OR in RubyCocoa myself I can say that
> it's safer for OR to expect the user to run the code in a separate
> thread. It makes more sense to me than trying it the other way.
>
> I played around with different approaches to handle this, since it was
> of course the first thing that you come across when dealing with
> network requests. I used both a normal thread (NSThread) and an
> NSLoadOperationQueue to handle the network tasks in the background.
> You have to do more work to ensure that you're always updating the GUI
> from the main thread, when you're handling events from the queue or
> the thread, but that's what performSelectorOnMainThread is for.

This is the approach that we currently take, though it's something we
are eager to improve upon.

In order to keep the UI responsive, my preference is to use the
NSOperationQueue. I'll create a ticket to add this
as part of the sample application, and possibly as part of the framework.

Here is some sample code for now: http://gist.github.com/66593

The above linked gist sets up a single operation queue in the app
delegate and then makes use of that queue to
load the list of people from ObjectiveResource and refresh the table
view as an NSOperation.

Note the use of "performSelectorOnMainThread:" in the method that gets
run as an NSOperation. This is because the UITableView
"reloadData" method needs to be called in the UI thread.

Also note that the "people" property should be declared as an atomic
property since it will now be accessed from multiple threads. One
possible way around that would be to call the setter using the same
"performSelectorOnMainThread" message used for the tableView.

Adam

unread,
Mar 1, 2009, 2:45:03 PM3/1/09
to ObjectiveResource
Hi Josh, your suggestion worked great in a project I'm working on so I
went ahead and made a first attempt at integrating some of this into
the framework. What I added to my local copy of ObjectiveResource is
a singleton called ConnectionManager that encapsulates the
NSOperationQueue with a few helper methods. With something like this
in the framework, the developer is responsible only for creating a
relatively simple method like the one in your example:

- (void) loadPeople {
self.people = [Person findAllRemote];
[tableView performSelectorOnMainThread:@selector(reloadData)
withObject:nil waitUntilDone:NO];
}

With that complete, it can be executed as follows:

[[ConnectionManager sharedInstance] runJob:@selector(loadPeople)
onTarget:self];

I've verified this runs asynchronously as expected while keeping a
responsive UI during the operation and does not reintroduce the crash
that was fixed here:

http://yfactorial.lighthouseapp.com/projects/18393/tickets/39-crash-when-calling-findallremote-in-rapid-succession

Please let me know if you have any suggestions for how this is being
implemented and if you would like me to commit it to my fork so you
can see the code. Thanks!

Adam

Adam

unread,
Mar 2, 2009, 6:03:41 PM3/2/09
to ObjectiveResource
Thanks for the help via email, I've made this commit with the new
class:

http://github.com/adamalex/objectiveresource/commit/28ea8bc3097e5f999e504865ac01e4039d85eb12

And, updated the new ticket as well:

http://yfactorial.lighthouseapp.com/projects/18393/tickets/57-async-connection-manager

Adam

On Mar 1, 2:45 pm, Adam <adama...@gmail.com> wrote:
> Hi Josh, your suggestion worked great in a project I'm working on so I
> went ahead and made a first attempt at integrating some of this into
> the framework.  What I added to my local copy of ObjectiveResource is
> a singleton called ConnectionManager that encapsulates the
> NSOperationQueue with a few helper methods.  With something like this
> in the framework, the developer is responsible only for creating a
> relatively simple method like the one in your example:
>
> - (void) loadPeople {
>     self.people = [Person findAllRemote];
>     [tableView performSelectorOnMainThread:@selector(reloadData)
> withObject:nil waitUntilDone:NO];
>
> }
>
> With that complete, it can be executed as follows:
>
> [[ConnectionManager sharedInstance] runJob:@selector(loadPeople)
> onTarget:self];
>
> I've verified this runs asynchronously as expected while keeping a
> responsive UI during the operation and does not reintroduce the crash
> that was fixed here:
>
> http://yfactorial.lighthouseapp.com/projects/18393/tickets/39-crash-w...
Reply all
Reply to author
Forward
0 new messages