2012-10-16 201 views
3

我在iOS應用程序中啓用iCloud並首次啓動應用程序時,當我按下應用程序中的任何視圖時,應用程序凍結約5秒鐘。我遵循this教程,在我的應用程序中啓用iCloud並使用核心數據同步數據。在添加iCloud同步之前,我沒有遇到這個問題。這隻發生在首次發佈時,而不是其他應用程序的發佈。 iCloud同步確實發生。問題是應用程序凍結。iCloud啓用時首次啓動iOS應用程序時凍結

以下是管理我的應用程序委託中的同步的代碼。

- (NSURL *)applicationDocumentsDirectory 
{ 
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
} 

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    /*if (persistentStoreCoordinator == nil) { 
     NSURL *storeURL = [NSURL fileURLWithPath:[self dataStorePath]]; 

     persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; 

     NSError *error; 
     if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 
      NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]); 
      abort(); 
     } 
    } 
    return persistentStoreCoordinator;*/ 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 

    if ((persistentStoreCoordinator != nil)) { 
     return persistentStoreCoordinator; 
    } 

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    NSPersistentStoreCoordinator *psc = persistentStoreCoordinator; 

    // Set up iCloud in another thread: 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // ** Note: if you adapt this code for your own use, you MUST change this variable: 
     NSString *iCloudEnabledAppID = @"48S27G4A2S.com.maxned.iDownloadBlog"; 

     // ** Note: if you adapt this code for your own use, you should change this variable: 
     NSString *dataFileName = @"DataStore.sqlite"; 

     // ** Note: For basic usage you shouldn't need to change anything else 

     NSString *iCloudDataDirectoryName = @"Data.nosync"; 
     NSString *iCloudLogsDirectoryName = @"Logs"; 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 
     NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName]; 
     NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil]; 

     if (iCloud) 
     { 
      //NSLog(@"iCloud is working"); 

      NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]]; 

      /*NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID); 
      NSLog(@"dataFileName = %@", dataFileName); 
      NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName); 
      NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName); 
      NSLog(@"iCloud = %@", iCloud); 
      NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);*/ 

      if ([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) { 
       NSError *fileSystemError; 
       [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
         withIntermediateDirectories:YES 
             attributes:nil 
              error:&fileSystemError]; 

       if (fileSystemError != nil) { 
        NSLog(@"Error creating database directory %@", fileSystemError); 
       } 
      } 

      NSString *iCloudData = [[[iCloud path] 
            stringByAppendingPathComponent:iCloudDataDirectoryName] 
            stringByAppendingPathComponent:dataFileName]; 

      //NSLog(@"iCloudData = %@", iCloudData); 

      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 
      [options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey]; 
      [options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey]; 

      [psc lock]; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
       configuration:nil 
       URL:[NSURL fileURLWithPath:iCloudData] 
       options:options 
       error:nil]; 

      [psc unlock]; 

     } else { 

      NSLog(@"iCloud is NOT working - using a local store"); 
      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 

      [psc lock]; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
       configuration:nil 
       URL:localStore 
       options:options 
       error:nil]; 

      [psc unlock]; 

     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil]; 
     }); 
    }); 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

    return persistentStoreCoordinator; 
} 

/*- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (managedObjectContext == nil) { 
     NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator; 
     if (coordinator != nil) { 
      managedObjectContext = [[NSManagedObjectContext alloc] init]; 
      [managedObjectContext setPersistentStoreCoordinator:coordinator]; 
     } 
    } 
    return managedObjectContext; 
}*/ 

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (managedObjectContext != nil) { 
     return managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 

    if (coordinator != nil) { 
     NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

     [moc performBlockAndWait:^{ 
      [moc setPersistentStoreCoordinator: coordinator]; 
      [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator]; 
     }]; 
     managedObjectContext = moc; 
    } 

    return managedObjectContext; 
} 

- (void)mergeChangesFrom_iCloud:(NSNotification *)notification 
{ 
    //NSLog(@"Merging in changes from iCloud..."); 

    NSManagedObjectContext* moc = [self managedObjectContext]; 

    [moc performBlock:^{ 

     [moc mergeChangesFromContextDidSaveNotification:notification]; 

     NSNotification* refreshNotification = [NSNotification notificationWithName:@"SomethingChanged" 
      object:self 
      userInfo:[notification userInfo]]; 

     [[NSNotificationCenter defaultCenter] postNotification:refreshNotification]; 
    }]; 
} 

回答

3

要解決此問題,我將代碼更改爲放入另一個線程。

dispatch_queue_t mainQueue = dispatch_get_main_queue(); 
     dispatch_async(mainQueue, ^{ 

      NSFileManager *fileManager = [NSFileManager defaultManager]; 
      NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName]; 
      NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil]; 

      if (iCloud) 
      { 
       //NSLog(@"iCloud is working"); 

       NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]]; 

       /*NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID); 
       NSLog(@"dataFileName = %@", dataFileName); 
       NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName); 
       NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName); 
       NSLog(@"iCloud = %@", iCloud); 
       NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);*/ 

       if ([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) { 
        NSError *fileSystemError; 
        [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
          withIntermediateDirectories:YES 
              attributes:nil 
               error:&fileSystemError]; 

        if (fileSystemError != nil) { 
         NSLog(@"Error creating database directory %@", fileSystemError); 
        } 
       } 

       NSString *iCloudData = [[[iCloud path] 
             stringByAppendingPathComponent:iCloudDataDirectoryName] 
             stringByAppendingPathComponent:dataFileName]; 

       //NSLog(@"iCloudData = %@", iCloudData); 

       NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
       [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
       [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 
       [options setObject:iCloudEnabledAppID forKey:NSPersistentStoreUbiquitousContentNameKey]; 
       [options setObject:iCloudLogsPath forKey:NSPersistentStoreUbiquitousContentURLKey]; 

       [psc lock]; 

       [psc addPersistentStoreWithType:NSSQLiteStoreType 
            configuration:nil 
              URL:[NSURL fileURLWithPath:iCloudData] 
             options:options 
              error:nil]; 

       [psc unlock]; 

      } else { 

       NSLog(@"iCloud is NOT working - using a local store"); 
       NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
       [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
       [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 

       [psc lock]; 

       [psc addPersistentStoreWithType:NSSQLiteStoreType 
            configuration:nil 
              URL:localStore 
             options:options 
              error:nil]; 

       [psc unlock]; 
      } 
     }); 
+0

不要忘記將它標記爲接受的答案(如果是這樣)。 – Shmidt

+0

感謝提醒我 –

+0

我沒有看到另一個線程。你的意思是主線程? – Shmidt

0

如果此代碼在主線程上運行,那可能是您的問題。

從第一次(或任何)啓動時調用此代碼的位置?

+0

它在managedObjectContext中調用:如果您看,persistentStoreCoordinator中的代碼正在第二個線程中運行 –

0

做一些自己搜索,看起來像這實際上是預期的行爲。正如其他人所說的App killed by SIGKILL when changing privacy settings和這裏:https://devforums.apple.com/message/715855

這是記錄不完善,但按設計工作。 「任何權限變更iOS都會終止你的應用程序,這樣你就不會在任何權限之前進行操作,例如讓用戶給你聯繫人的權限,然後他們爲你的應用程序提供背景,然後去改變那麼,如果你現在不知道你有權限的話,你就可以運行,所以iOS只會終止應用程序。「

「但它不會崩潰,它只是被迫重啓,你會得到一個SIGKILL消息,但沒有崩潰日誌。」

相關問題