tags:

views:

773

answers:

2

Hi,

I've released an app update which does an upgrade of the database ie. executes a script file in the bundle that adds a column to existing table , etc. I've tested this by deploying previous version builds on my device from xcode and then deploying the latest version. The upgrade worked fine.

Yesterday my distribution build got accepted to app store. When I start it up , my nightmare scenario materialized , it fails during DB upgrade! I've checked the distribution build and the upgradeSQL file is there , so it doesn't seem to be a missing resource file all though I'm not sure. I have no idea how I should debug this. What is the difference between a distribution build from app store and a release/debug build deployed from xcode , apart from code signing? Doesn't make sense to me.

This is my crash log and the code that fails:

0   libSystem.B.dylib               0x3141d414 pread + 20
1   libsqlite3.0.dylib              0x303a2154 unixRead + 40
2   libsqlite3.0.dylib              0x303bd7c4 sqlite3PagerAcquire + 3748
3   libsqlite3.0.dylib              0x303c7718 sqlite3BtreeNext + 260
4   libsqlite3.0.dylib              0x303c7b84 sqlite3BtreeNext + 1392
5   libsqlite3.0.dylib              0x304272b8 sqlite3VdbeExec + 38668
6   libsqlite3.0.dylib              0x30428944 sqlite3Step + 504
7   libsqlite3.0.dylib              0x303ecbc4 sqlite3_exec + 600
8   MyApp                       0x00046ae4 +[DBUpgradeService executeUpgradeScript:] (DBUpgradeService.m:94)
9   MyApp                       0x000469aa +[DBUpgradeService upgradeV1_0ToV1_1] (DBUpgradeService.m:67)
10  MyApp                       0x0004687a +[DBUpgradeService upgradeDBIfNecessary] (DBUpgradeService.m:27)
11  MyApp                       0x000021ec -[MyAppAppDelegate applicationDidFinishLaunching:] (MyAppAppDelegate.m:49)
12  UIKit                           0x30a4ef24 -[UIApplication performInitializationWithURL:asPanel:] + 160
13  UIKit                           0x30a57dec -[UIApplication _runWithURL:] + 644
14  Foundation                      0x306945a2 __NSFireDelayedPerform + 326
15  CoreFoundation                  0x30269d88 CFRunLoopRunSpecific + 2642
16  CoreFoundation                  0x30269320 CFRunLoopRunInMode + 44
17  GraphicsServices                0x31567e58 GSEventRunModal + 268
18  UIKit                           0x30a4fa6c -[UIApplication _run] + 520
19  UIKit                           0x30a591d0 UIApplicationMain + 1132
20  MyApp                       0x00002090 main (main.m:20)
21  MyApp                       0x0000202c start + 44



+ (BOOL) executeUpgradeScript:(NSString*) scriptName{
    NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
    NSString *scriptPath = [resourcePath stringByAppendingPathComponent:scriptName];

    NSString* upgradeScript = [NSString stringWithContentsOfFile:scriptPath];
    NSArray* lines = [upgradeScript componentsSeparatedByString:@"\n"];
    //begin transaction
    NSString* begin = [NSString stringWithString:@"BEGIN TRANSACTION"];

    sqlite3_exec([DatabaseManager getDatabase], begin.UTF8String , nil , nil , nil);
    BOOL failed = NO;
    for( NSString* line in lines) {
     const char *sql = line.UTF8String;
     char* error = nil;
     sqlite3_exec([DatabaseManager getDatabase], sql , nil , nil , &error); //THIS LINE FAILS
     if(error != nil) {
      NSLog([NSString stringWithCString:error]);
      failed = YES;
      break;
     }
    }

    if(failed){
     return NO;
    }
    else{
     NSString* commit = [NSString stringWithString:@"COMMIT"];
     sqlite3_exec([DatabaseManager getDatabase], commit.UTF8String , nil , nil , nil);
     return YES;

    }
}
+1  A: 

You aren't allowed to modify files in your application bundle (see epatel's link). As part of your build process, the app gets signed, and modifying files in the bundle will break the signature.

You should be using your application's document directory. You should replace your resourcePath assignment with:

NSString *resourcePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Martin Gordon
This is really strange. How did the app get approved in the first place?
Kriem
It does seems a bit strange, but given that Apple is probably running a special version of the OS, they probably didn't pick up on the problems caused by changes to the app bundle.
Martin Gordon
Sounds like a bug report to me. :)
Kriem
Hi Martin. I'm confused. Where am I modifying files in my application bundle? I'm just reading an SQL text file from the bundle and executing the lines in sqlite database. That database resides in the document folder.
Maxm007
My mistake. Can you post the source to [DatabaseManager getDatabase]? Alternatively, can you see if [[NSFileManager defaultManager] fileExistsAtPath:scriptPath] returns YES? Also, UTF8String is not a property of NSString so you should be using [line UTF8String] instead of line.UTF8String.
Martin Gordon
Hmm , well spotted, strange that it works anyway with property UTF8String.But anyway, we've found the solution.
Maxm007
+1  A: 

If the upgrade of the DB takes to long time in the launch phase an app can be kicked out.

One way to resolve such a problem could be to put the upgrade in a NSThread

- (void)upgradeSomething:(id)sender
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

  // Do something here that takes time

  // and maybe signal when done with some flag or thing...

  [pool release];
}

- (void)awakeFromNib
{
    // The usual stuff

    // and detach a NSThread for upgrade 

    [NSThread detachNewThreadSelector:@selector(upgradeSomething:) 
                             toTarget:self 
                           withObject:nil]
}

Read here for reason for keeping the event loop active.

epatel
Yes I figured it out myself too. It was indeed a timer forcing my app to crash when upgrading takes too long. I run the DB Upgrading on a separate thread now so the applicationDidLaunch call can return and all was gravy. I suspect the iphone os only applies the timer to distribution builds without debugger attached.You put me on the right track with the Ad Hoc deployment via iTunes which showed me the log line. I've pulled my app of the app store and submitted a new update. Be up and running by next week saturday. Thank you very much everybody.
Maxm007