I've run into exactly this problem when testing views that contain
UIWebView objects. UIWebView and UITextView apparently have some
similarities in their internal workings; as far as I can tell they're
both trying to access a thread that the applications sets up and
dedicates to web-related requests; in both cases they try to access
this thread upon instantiation. Unfortunately, access to this thread
is limited to calls from the main thread. Since Cedar runs its specs
in a background thread the very act of trying to instantiate a view
that contains a UIWebView or UITextView causes this error.
There are two (as far as I know) solutions for this. First, you can
run your specs with the CEDAR_HEADLESS_SPECS environment variable set.
This prevents the error because of the odd way the simulator works.
In short, running headless prevents the application from starting the
simulator's UI process. When the UI process isn't running all
UI-related SDK calls simply execute the stubs in the
simulator-specific UIKit SDK, the code never instantiates a real
UIWebView (or UITextView), and the specs don't crash.
The second solution is to stub out the UITextView class yourself.
This is more work, but allows you to keep using the UI spec runner, if
you prefer that. As an example, here are the files I've created to
stub out UIWebView for specs:
http://github.com/pivotal/PivotalCoreKit/blob/master/Spec/UI/UIWebViewSpec%2BSpec.m
http://github.com/pivotal/PivotalCoreKit/blob/master/SpecHelperLib/Extensions/UIWebView%2BSpec.h
http://github.com/pivotal/PivotalCoreKit/blob/master/SpecHelperLib/Extensions/UIWebView%2BSpec.m
I haven't entirely finished the stub, but it should get you going in
the right direction if you want to go that way.
As for running Cedar specs on the main thread, I've been noodling over
the idea of writing a test runner that wil schedule each spec on the
run loop individually, rather than running them all together in the
background. Something like this would also theoretically make it
possible to test asynchronous calls (like performSelector:afterDelay:)
that depend on the run loop. It's just one of those ideas I haven't
had a chance to sit down and write the code for yet.
For anyone that's curious you can see what I wrote here:
http://gist.github.com/633459
Wes
Regards,
Wes
On Tue, Oct 19, 2010 at 1:03 PM, Adam Milligan