Crash - "Collection <CALayerArray: 0x645dfc0> was mutated while being enumerated."
Asked Answered
S

1

7

Goal is to "launch a spinner graphic at start of viewWillAppear that loads data before showing the tableview" so the user doesn't wonder why there's a delay before seeing the table. I.e. a UIActivityIndicatorView has been added to the window, and I just want to set the alpha to hide/show it.

I get this strange error when starting a thread to make sure the "spinning gears" imageview (tag=333) gets shown, before moving on to load/calculate stuff in viewWillAppear.

I don't get it on every call to [appdel addGearz] and [appdel removeGearz], it happens for both these, and it's random. It can happen after 2 viewWillAppears, or after 15. If I comment out the line that sets the alpha, everything works.

A typical viewWillAppear looks something like this,

[super viewWillappear];
self.title=@"Products listing"; //and other simple things
[appdel addGearz];
[self getProducts];
[self getThumbnails];
[myTableView reloadData]; //in case view already loaded and coming back from subview and data changed

And here is the code that crashes if the lines with .alpha are not commented out

-(void)addGearz {
    [NSThread detachNewThreadSelector:@selector(gearzOn) toTarget:self withObject:nil];
}

-(void)removeGearz {
    [NSThread detachNewThreadSelector:@selector(gearzOff) toTarget:self withObject:nil];
}

- (void)gearzOn {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [window viewWithTag:333].alpha=1.0;
        //
        //  [[window viewWithTag:333] setNeedsDisplay];
    [pool drain];
}

- (void) gearzOff {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [window viewWithTag:333].alpha=0.0;
        //
        //  [[window viewWithTag:333] setNeedsDisplay];
    [pool drain];
}

I've used someone else's code, so... anything obvious you can see? Surely I must be able to change alpha of UIViews in a thread? Do I need to "embed" the alpha-change in some "stop enumerating while I change this"-code?

I made it not crash by moving that alpha-change-line to above the pool alloc or below the [pool drain], but then I get a lot of "autoreleased with no pool in place - just leaking"-messages.

Apparently, there's something I don't understand about this thread code.

Southerner answered 21/1, 2011 at 10:8 Comment(0)
N
8

You must not try to modify the UI on a separate thread. UI should only be manipulated on the main thread.

Instead of detaching a new thread, you should use performSelectorOnMainThread:withObject:waitUntilDone:. This will ensure that the method will be called on the proper thread.

Noddy answered 21/1, 2011 at 11:11 Comment(3)
[self performSelectorOnMainThread:@selector(gearzOn) withObject:nil waitUntilDone:YES]; does not update visibility immediately, which is the whole idea - since viewWillAppear will do all of its loading before the view is pushed, the user should be aware that something's happening.Southerner
Didn't appear with [window setNeedsDisplay]; either. Using an alpha UIAnimation worked, though. (Quick fade.) Any ideas why that works but not setting the alpha and asking the window to update? Will mark your answer as correct, it solved the problem. Thanks!Southerner
I guess it has a relation with the layers's display queue and the way animations are dealt with. Good to know that UIAnimation did the trick.Noddy

© 2022 - 2024 — McMap. All rights reserved.