Search code examples
iosanimationcore-animation

Objective-C: Why does my app not perform any animations and do wonky unexpected things when I open up my app occasionally?


So this is hard to explain, but... Sometimes when I open up my app it just ignores all animations and does the "animation block" without it being an animation, so it does it instantly for every single animation through the entire app. I'm confused on why this is happening, because other times when I open up the app, it works perfectly fine but occasionally when I open up the app it just blows up in my face and ignores all animations.

The problem started when I added this line of code:

[weakSelf.tableView performSelectorInBackground:@selector(reloadData) withObject:nil];

Can someone please help on why this is happening?


Solution

  • This line of code:

    [weakSelf.tableView performSelectorInBackground:@selector(reloadData) withObject:nil];
    

    Is guaranteed to "explode" in unpredictable ways.

    Quoting the documentation for performSelectorInBackground::

    creates a new thread in your application, putting your application into multithreaded mode if it was not already. The method represented by aSelector must set up the thread environment just as you would for any other new thread in your program.

    The reloadData method does not "setup the thread environment" and therefore will screw up badly if you execute it.

    Also, quoting the documentation for reloadData:

    Marks the table view as needing redisplay, so it will reload the data for visible cells and draw the new values.

    Notice the part I highlighted in bold. Drawing to the screen must happen on the main thread or else everything will screw up. Screen drawing on a background thread is unreliable and should not be done.

    This part is particularly bad, because depending on what is going on in other threads, drawing from a background thread will usually work but often it won't work and you'll see exactly the kind of problems you've described.

    So, to fix your code, change this line of code:

    [weakSelf.tableView performSelectorInBackground:@selector(reloadData) withObject:nil];
    

    To this:

    dispatch_async(dispatch_get_main_queue(), ^(void){
      [weakSelf.tableView reloadData];
    });
    

    That way the reloadData operation will perform on the main thread (also known as a queue) and everything should be good.