2013-10-02 3 views
0

У меня есть приложение с двумя отдельными TableViewControllers («TVC»), которые обращаются к тем же таблицам SQL CoreData. Пользователь вызывает TVC, нажимая кнопки в родительском ViewController. Однако записи, записанные в CoreData по вызовам подкласса NSManagedObject с помощью первого TVC, не были распознаны вторым TVC. Я решил, что создаю отдельные экземпляры моего UIManagedDocument, поэтому начал создавать экземпляр UIManagedDocument в родительском VC и передал документ в соответствующий TVC.Приложение iPhone падает при сохранении изменений в UIManagedObjectDocument

Теперь, когда я пытаюсь сохранить документ после записи записей, приложение падает, даже если я нахожусь в основном потоке, где был первоначально создан экземпляр документа.

Я иду об этом неправильно?

Вот родитель ViewController

// 
#import "ITrackViewController.h" 
#import "AthleteSearchTVController.h" 

@interface ITrackViewController() 

@end 

@implementation ITrackViewController 

@synthesize myFirstName = _myFirstName; 
@synthesize myLastName = _myLastName; 

@synthesize athleteDatabase = _athleteDatabase; 


-(void) setAthleteDatabase:(UIManagedDocument *)athleteDatabase 
{ 
    if(_athleteDatabase != athleteDatabase) 
    { 
     _athleteDatabase = athleteDatabase; 
    } 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
// Do any additional setup after loading the view, typically from a nib. 
    if (!self.athleteDatabase) { // for demo purposes, we'll create a default database if none is set 

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"Default Athlete Database"]; 
    NSLog(@"url for dataBase is %@.",url); 
    // url is now "<Documents Directory>/Default Athlete Database" 
    self.athleteDatabase = [[UIManagedDocument alloc] initWithFileURL:url]; // setter will create this for us on disk 
    } 

} 

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if ([segue.identifier isEqualToString:@"BeginSearch"]) { 
     NSLog(@"firstName is %@ and lastName is %@.",firstName.text, lastName.text); 

     NSString *checkFirstName = [firstName.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 
     NSString *checkLastName = [firstName.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 

     if ([checkFirstName length] < 1 || [checkLastName length] < 1) { 
     NSLog(@"Must include a value for both first and last names."); 
     } else { 
      [self dismissKeyboard:sender]; 
      myFirstName = firstName.text; 
      myLastName = lastName.text; 

      UIManagedDocument *sharedAthleteDataBase = [self sharedDatabase]; 

      NSString *searchName = [myFirstName stringByAppendingString:@"%20"]; 
      searchName = [searchName stringByAppendingString:myLastName]; 

     NSLog(@"searchName is %@ before segue.",searchName); 

      [segue.destinationViewController nameToSearchFor:searchName andUIManagedDoc:sharedAthleteDataBase]; 
     } 

    } 
} 

-(IBAction)dismissKeyboard:(id)sender 
{ 
[lastName endEditing:YES]; 
[firstName endEditing:YES]; 
} 

- (UIManagedDocument *) sharedDatabase 
{ 

    __block UIManagedDocument *managedDocument = nil; 

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    url = [url URLByAppendingPathComponent:@"AthleteData"]; 

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.athleteDatabase.fileURL path]]) { 
     // does not exist on disk, so create it 
     [self.athleteDatabase saveToURL:self.athleteDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) { 

      if(success){ 
       NSString* isMainThread; 
       if ([NSThread isMainThread]) { 
        isMainThread = @"on main thread."; 
       } else isMainThread = @"but not on main thread"; 
       NSLog(@"athleteDatabase did not exist, now created %@", isMainThread); 
       managedDocument = self.athleteDatabase; 
      } else { 
       NSLog(@"Error creating athleteDatabase"); 
      } 
     }]; 
    } else if (self.athleteDatabase.documentState == UIDocumentStateClosed) { 
     // exists on disk, but we need to open it 

     [self.athleteDatabase openWithCompletionHandler:^(BOOL success) { 

      if(success){ 
       NSString* isMainThread; 
       if ([NSThread isMainThread]) { 
        isMainThread = @"on main thread."; 
       } else isMainThread = @"but not on main thread"; 
       NSLog(@"athleteDatabase was closed, is now open %@", isMainThread); 
       managedDocument = self.athleteDatabase; 

      } else NSLog(@"Error opening closed athleteDatabase"); 

     }]; 
    } else if (self.athleteDatabase.documentState == UIDocumentStateNormal) { 
     // already open and ready to use 
     managedDocument = self.athleteDatabase; 
    } 

    return managedDocument; 
} 

@end 

Вот ТВЦ, что делает звонки на NSManagedObject Sub-класса первого извлечения данных из веб-API, а затем записать его на CoreData.

- (void)fetchAthleteSearchResultsIntoDocument:(UIManagedDocument *)document 
            whereNameIs:(NSString *)athleteName 

{ 
    dispatch_queue_t fetchQ = dispatch_queue_create("Athlete fetcher", NULL); 
    dispatch_async(fetchQ, ^{ 
     NSString* isMainThread; 
     if ([NSThread isMainThread]) { 
      isMainThread = @"on main thread."; 
     } else isMainThread = @"but not on main thread"; 
     NSLog(@"Preparing to get records %@", isMainThread); 
     NSArray *athleteRecords; 
     athleteRecords = [AthleticNetDataFetcher searchForMyAthleteWithName:athleteName]; 

     [document.managedObjectContext performBlockAndWait:^{ // perform in the NSMOC's safe thread (main thread) 
      int iCount = 0; 
      for (NSDictionary *athleteInfo in athleteRecords) { 

       [ResultsForAthleteSearch resultsWithAthleteInfo:athleteInfo inManagedObjectContext:document.managedObjectContext 
              numberForSorting:iCount]; 
       iCount = iCount + 1; 
       // table will automatically update due to NSFetchedResultsController's observing of the NSMOC 
      } 

      NSString* isMainThread; 
      if ([NSThread isMainThread]) { 
       isMainThread = @"on main thread."; 
      } else isMainThread = @"but not on main thread"; 
      NSLog(@"Preparing to save results %@", isMainThread); 

      [document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL]; 

     }]; 
    }); 

} 

Тренажер сбой при вызове [документ saveToURL: document.fileURL forSaveOperation: UIDocumentSaveForOverwriting completionHandler: NULL];

Журнал, который частично приведен ниже, говорит, что я на главной теме. Я не могу понять, почему это должно потерпеть крах. Это не сбой, если я прокомментирую вызов saveToURL и полагаюсь на автосохранение.

2013-10-02 13:46:22.459 iTrackTest[14989:c07] url for dataBase is file://localhost/Users/Phlipo/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/53E19DAE-6D2B-4B7F-A633-55C2BCA95AC5/Documents/Default%20Athlete%20Database/. 

2013-10-02 13:46:31.031 iTrackTest[14989:c07] url for dataBase is file://localhost/Users/Phlipo/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/53E19DAE-6D2B-4B7F-A633-55C2BCA95AC5/Documents/Default%20Athlete%20Database/. 

2013-10-02 13:46:31.039 iTrackTest[14989:61f] Preparing to get records but not on main thread 

2013-10-02 13:46:31.065 iTrackTest[14989:c07] athleteDatabase was closed, is now open on main thread. 
2013-10-02 13:46:31.620 iTrackTest[14989:61f] [AthleticNetDataFetcher executeSearchRequest:] received { 
. 
[A bunch of data in JSON format]. 
. 
} 


2013-10-02 13:46:31.633 iTrackTest[14989:c07] Preparing to save results on main thread. 
2013-10-02 13:47:23.258 iTrackTest[16150:3f07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.' 

Я не сталкивался с этой ошибкой NSPErsistence при создании экземпляра MOD в TVC. Может быть, мне нужен более явный помощник DataBase?

Заранее благодарим за любую помощь.

ответ

0

Получил это немного, но вот что я понял.

Я помнил, что в Android я использовал классы-помощники SQL. Пол Хегарти рекомендует этот подход с некоторыми оговорками для простых приложений.

Tim Roadley's tutorial - отличный ресурс по этой теме.

Смежные вопросы