4

I have a simple reading app that uses fmdb to talk to the database and then fill up a UIWebview with text. Since the glorious advent of ios 5 it runs very poorly...

When I am change chapters in my book via a segmentedControl tap. In ios 4.3, it was SUPER fast. Now, as you can see below, it isn't:

enter image description here

So obviously things are loading slow, but I don't know how to read the results of the speed test. Which method is the main culprit? What do I need to do to optimize the app? Is there anything else I can do to understand where exactly the hang-ups are?

I am having such a hard time with fmdb and ios 5 that I am considering other options. Should I just scrap fmdb? And go for the direct ios sqlite db approach?

I am finding the instruments tool to be useful, but very hard to understand and use.

UPDATE

Here is the change chapter method:

- (IBAction) changeChapter:(id)sender {
if ([prevNext selectedSegmentIndex] == 0) {
    //previous
    [self setCurrentChapter:(currentChapter-1)];
} else {
    //next
    [self setCurrentChapter:(currentChapter+1)];
}
[self refreshUI];
}

UPDATE 2:

Here is the code that instruments is telling me is the problem. It is the next method that fmdb uses to iterate through the FMResultSet:

- (BOOL) next {

int rc;
BOOL retry;
int numberOfRetries = 0;
do {
    retry = NO;

    rc = sqlite3_step(statement.statement); //Instruments says this is 100% the problem

    if (SQLITE_BUSY == rc) {
        // this will happen if the db is locked, like if we are doing an update or insert.
        // in that case, retry the step... and maybe wait just 10 milliseconds.
        retry = YES;
        usleep(20);

        if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {

            NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
            NSLog(@"Database busy");
            break;
        }
    }
    else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
        // all is well, let's return.
    }
    else if (SQLITE_ERROR == rc) {
        NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
        break;
    } 
    else if (SQLITE_MISUSE == rc) {
        // uh oh.
        NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
        break;
    }
    else {
        // wtf?
        NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
        break;
    }

} while (retry);


if (rc != SQLITE_ROW) {
    [self close];
}

return (rc == SQLITE_ROW);
}

FMDB is all I've ever known as far as sqlite goes, is it even worth it? Should I just scrap it and move to the cocoa-touch sqlite api's?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Lizza
  • 2,769
  • 5
  • 39
  • 72
  • Kinda looks like 40% of your time is in UIApplication sendEvent. But that's probably because your changeChapter method is doing a lot of the same operations again and again (though can't tell precisely what operations -- are you actually doing performSelector that much, or is it something that the compiler generated?). – Hot Licks Dec 13 '11 at 17:32
  • Thanks for the comment. Looks to be compiler generated. I'm not calling performSelector at all during the nextChapter method process. – Lizza Dec 13 '11 at 17:39
  • You should be aware that although you've blanked out some of the identifying information in the image, you haven't blanked out all of it. You are better off with solid bars anyway, the lines you've used aren't enough to obscure the text. – Jim Dec 13 '11 at 18:00
  • I had the same issue using sqlite directly, and it reduced performance by at least an order of magnitude in iOS 5. So it's not FMDB. – John Feb 13 '12 at 07:54

1 Answers1

2

Ok I was actually able to get this information from someone on the FMDB mailing list. He suggested that I add an index to my db tables that were being called frequently, and that fixed it!

Apparently Apple changed the version of sqlite in iOS 5.

From the FMDB post:

Creating an index in sqlite is easy - see sqlite.org for the syntax. The trick is figuring out what index(es) to create. In my case I had a query like: select a,b,c from x where sid=somevalue; sid was not the primary key for the table so there wasn't an index on it. Adding an index on sid made that query much faster since the index allows it to quickly find tuples. Note that indexes can slow down updates, inserts, and deletes on the table so don't just randomly add indexes to your tables. Look at your queries and see what columns are used in the where clause of your queries.

Lizza
  • 2,769
  • 5
  • 39
  • 72
  • Can you be a bit more precise? How would I add an index to a frequently used table? Thanks – Stavash Apr 04 '12 at 16:33
  • Thanks again :) Correct me if I'm wrong but this means that you somehow need to manage your queries in a way that you know which index you're looking for, right? In my case, I'm working with data that has some kind of unique integer identifier - does this count for an index as well? – Stavash Apr 04 '12 at 17:14