0

In the iOS app I am currently working on, the app hits a database to retrieve information every time the page changes. While waiting for the query to execute and the information from the query to populate the fields on the page there is supposed to be a view that popups, animates and says loading. Originally there was a method that checked if there was an internet connection, and if there was would display the popup and then another method would execute the query. These where threaded like so

[NSThread detachNewThreadSelector:@selector(appStartedLoading) toTarget:self withObject:nil]; 

However this lead to a crash problem about 10% of the time. I don't entirely understand that problem, but I think it was because detaching a new thread like that would sometimes (not always) cause a subview to be added from a thread that's not the main thread. that's kind of a sub question here, wether my theory is logical or not.

Either way we got rid of that method of doing things and just called the methods one at a time without threading. Like this

[self appStartedLoading];
[self performQuery]; //fake placeholder method for examples sake.

But this caused the loading screen to show up after the next page was already display and the query was already executed, presumably because the app was too busy with the query. I've tried running the query in a separate thread the way the subview used to but it did not change it. I've tried running the appStartedLoading method on the main thread and telling it block i.e.

[self performSelectorOnMainThread:@selector(appStartedLoading) withObject:nil waitUntilFinished: YES]; 

I would think that because it is told to block it wouldn't perform the query till after the subview is added and animating then but it still changes pages first and then displays the loading screen. I've also tried putting little loops in the method to make it not finish till the subview has been added but they finish right away even though the subview does not show up on the screen. The loop is this.

while([[[self.window.subviews objectAtIndex:0] subviews] indexOfObject:loaderView] == NSNotFound)
    {
        i++;
        NSLog(@"this %d", i);
        [[self.window.subviews objectAtIndex:0] addSubview:loaderView];
    }  

It makes sense to me that in only executes once cuz I tell it to add the subview, but why the heck isn't it appearing after adding it? I'm not honestly good at programming yet and very confused by what's going on here, if someone could help shed some light here and point me in the right direction of what's going on behind the scenes that'd be awesome.

here's the error log from crashes

 bool _WebTryThreadLock(bool), 0xc8a7fa0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
1   WebThreadLock
2   -[UITextView setFrame:]
3   UIViewCommonInitWithFrame
4   -[UIView initWithCoder:]
5   -[UIScrollView initWithCoder:]
6   -[UITextView initWithCoder:]
7   UINibDecoderDecodeObjectForValue
8   -[UINibDecoder decodeObjectForKey:]
9   -[UIRuntimeConnection initWithCoder:]
10  UINibDecoderDecodeObjectForValue
11  UINibDecoderDecodeObjectForValue
12  -[UINibDecoder decodeObjectForKey:]
13  -[UINib instantiateWithOwner:options:]
14  -[UIViewController _loadViewFromNibNamed:bundle:]
15  -[UIViewController loadView]
16  -[UIViewController view]
17  -[UIViewController contentScrollView]
18  -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:]
19  -[UINavigationController _layoutViewController:]
20  -[UINavigationController _startTransition:fromViewController:toViewController:]
21  -[UINavigationController _startDeferredTransitionIfNeeded]
22  -[UINavigationController __viewWillLayoutSubviews]
23  -[UILayoutContainerView layoutSubviews]
24  -[UIView(CALayerDelegate) layoutSublayersOfLayer:]
25  -[NSObject performSelector:withObject:]
26  -[CALayer layoutSublayers]
27  CA::Layer::layout_if_needed(CA::Transaction*)
28  CA::Context::commit_transaction(CA::Transaction*)
29  CA::Transaction::commit()
30  CA::Transaction::release_thread(void*) 
31  _pthread_tsd_cleanup
Joseph Waelchli
  • 60
  • 1
  • 10
  • Try the first way with the background thread and post the log message when it crashes. Also, your subview loop approach is way too complicated. If you need something to appear on top of everything else, add it as a subview of the view controller, or better yet, it's navigation controller's view. – CodaFi Jun 30 '12 at 20:55
  • Hey, thanks for the reply! I added it the navigations controller's view and that is a bit simpler so thanks for that. I'm working on getting the crash to happen again but so far it has not. I also added "performSelectorInBackground" to all my queries. I'm going to keep trying to get a crash and post the error log but do you think those changes might have been able to fix it? – Joseph Waelchli Jun 30 '12 at 22:21
  • Yes . I'll bet your while loop was spinning out of control (you never did call break). I'll put this up as the answer for you then. Just get back to me if it crashes. – CodaFi Jun 30 '12 at 22:22
  • I've run through the entirety of the app a few times now and I'm positive it would have crashed by now if the error was still around, so you can post the answer if you want. Thanks for the response! – Joseph Waelchli Jun 30 '12 at 22:32

1 Answers1

0

Try the first way with the background thread and post the log message when and if you can get it to crash. My hunch is that your while loop is spinning off into the blue because you never do actually call break; on that thing. Also, your subview loop approach is way too complicated. If you need something to appear on top of everything else, add it as a subview of the view controller, or better yet, it's navigation controller's view.

CodaFi
  • 43,043
  • 8
  • 107
  • 153
  • Well I have absolutely no idea what happened, but today when I was working on a different part of the app I suddenly got a near 80% rate of crashing changing pages. I have no idea what changed from yesterday, I have another guy working with me and he says he has not experienced any crashes yet, so we're pretty confused... I'm adding the error log to my original post – Joseph Waelchli Jul 01 '12 at 22:34
  • Hey, sorry for freaking out and re-asking you for help there I think. yesterday I removed one of the loops cuz I didn't think it was necessary and I forgot. I just put it back in and the crashing stopped. I'm just curious if by looking at the stack trace if you can confirm my theory that the deatchnewthreadselector is sometimes asking a thread other than the main to add the subview? if you have the time do you think you could explain to me or give me a resource to better understand how the detachnewthreadselector method works? – Joseph Waelchli Jul 01 '12 at 22:46
  • detatfhNewThreadWithSelector spawns a worker thread to process work off the main thread. Of course, in doing so, you run the risk of your resources being accessed in the background, or the background accessing resources on the main thread, which is bad, very bad. This is why we use Grand Central Dispatch for threading, instead. – CodaFi Jul 02 '12 at 15:21
  • Huh interesting, I'm going to look into what that is right now haha. Thanks for all your help! – Joseph Waelchli Jul 02 '12 at 15:45