2013-03-07 35 views
1

我正在使用NSOperationQueue & NSInvocationOperation調用我的UIViewController上的方法,然後調用另一個類中的方法,然後從Web分析XML文件並更新一些核心數據管理對象。核心數據獲取請求在後臺線程只能用於第一次獲取

此過程在我第一次運行應用程序時工作,但當我第二次調用該方法時(當再次顯示UIViewController時),它不會在XML解析器類中的executeFetchRequest語句之後執行任何行。下面是我使用的執行代碼:

我有一個UITableViewController是通吃了停車場靜態信息從我的核心數據存儲時,它加載:

- (void)viewDidLoad 
{ 
    NSLog(@"viewDidLoad"); 
    [super viewDidLoad]; 

    southeastCarparks = [[NSMutableArray alloc] init]; 
    southwestCarparks = [[NSMutableArray alloc] init]; 
    northeastCarparks = [[NSMutableArray alloc] init]; 
    northwestCarparks = [[NSMutableArray alloc] init]; 
    carparkLocations = [[NSMutableArray alloc] initWithObjects:southeastCarparks, southwestCarparks, northeastCarparks, northwestCarparks, nil]; 


    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription 
           entityForName:@"CarparkInfo" inManagedObjectContext:self.managedObjectContext]; 


    [fetchRequest setEntity:entity]; 
    NSError *error; 
    self.carparkInfos = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

    for (CarparkInfo *carpark in self.carparkInfos){ 
     if ([carpark.details.region isEqualToString:@"Southeast"]){ 
      [southeastCarparks addObject:carpark]; 
     } else if ([carpark.details.region isEqualToString:@"Southwest"]){ 
      [southwestCarparks addObject:carpark]; 
     } else if ([carpark.details.region isEqualToString:@"Northeast"]){ 
      [northeastCarparks addObject:carpark]; 
     } else if ([carpark.details.region isEqualToString:@"Northwest"]){ 
      [northwestCarparks addObject:carpark]; 
     } 
    } 

    [[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(loadXMLData) 
              name:@"appDidBecomeActive" 
              object:nil]; 
} 

然後當視圖出現我所說的loadXML的方法去網絡和從XML文件

- (void) viewDidAppear:(BOOL)animated 
{ 
    [self loadXMLData]; 
    NSLog(@"viewDidAppear"); 
} 


- (void) loadXMLData { 
    NSLog(@"loadXMLData"); 

    NSOperationQueue *queue = [NSOperationQueue new]; 
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self 
                 selector:@selector(loadXMLDataWithOperation) 
                      object:nil]; 
    [queue addOperation:operation]; 
} 

- (void) loadXMLDataWithOperation { 
    xmlParser = [[XMLParser alloc] loadXMLByURL:xmlFileURL]; 

    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; 
} 

在XMLParser的類獲得最新的停車位信息,我走xmlFileURL傳入,從網上檢索它,分析它,然後嘗試更新Co的可用空間重新數據存儲

-(id) loadXMLByURL:(NSString *)urlString 
{ 
    _carparks = [[NSMutableArray alloc] init]; 
    NSURL *url = [NSURL URLWithString:urlString]; 
    NSData *data = [[NSData alloc] initWithContentsOfURL:url]; 
    parser = [[NSXMLParser alloc] initWithData:data]; 
    parser.delegate = self; 
    [parser parse]; 
    return self; 
} 

- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 
    if (![elementName isEqualToString:@"carpark"]){ 
     return; 
    } 

    currentCarpark = [Carpark alloc]; 

    NSString *name = [attributeDict objectForKey:@"name"]; 
    currentCarpark.name = name; 

    NSString *spaces = [attributeDict objectForKey:@"spaces"]; 
    currentCarpark.spaces = spaces; 

    [self.carparks addObject:currentCarpark]; 
    currentCarpark = nil; 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 

    // set up the managedObjectContext to read data from CoreData 
    id delegate = [[UIApplication sharedApplication] delegate]; 
    self.managedObjectContext = [delegate managedObjectContext]; 

    NSEntityDescription *entity = [NSEntityDescription 
           entityForName:@"CarparkInfo" inManagedObjectContext:self.managedObjectContext]; 

    [fetchRequest setEntity:entity]; 
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"code=%@",name]]; 

    NSError *error; 
    CarparkInfo *cgCarpark; 

    // THIS IS THE LAST LINE TO BE EXECUTED THE 2ND TIME AROUND. THE APPLICATION DOESN'T THROW AN ERROR BUT DOESN'T GO ON TO UPDATE THE CARPARK OBJECT ON THE LINE AFTER 
    cgCarpark = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] lastObject]; 

    cgCarpark.availableSpaces = spaces; 
    error = nil; 
    if (![self.managedObjectContext save:&error]) { 
     //Handle any error with the saving of the context 
    } 
} 

我在做我的方式使用託管對象上下文的方式錯了嗎?

預先感謝任何幫助

+0

我想你會很高興展示如何調用這段代碼。 – 2013-03-07 02:05:54

+1

似乎你在這一行有一個死鎖。請給我們一個你正在運行這種方法的背景。 – 2013-03-07 07:11:17

+0

我已更新代碼以顯示如何調用該方法。有什麼辦法來檢查是否發生死鎖? – cullener 2013-03-07 11:36:00

回答

2

我覺得@Mark_Kryzhanouski是正確的之前,只寫了下面的語句,你有一個僵局。可能是因爲您正在多線程上訪問您的NSManagedObjectContext。你需要小心你的線程Core data。您的NSOperation將在後臺線程上運行,因此您撥打NSManagedObjectContext的電話將不會與viewDidLoad中的第一個電話處於同一線程。下面是Core Data併發一些參考材料...

Concurrency with Core DataCore Data Release Notes for OS X v10.7 and iOS 5.0

還有在WWDC 2012條的視頻,題目是一個很好的WWDC演講「會話214 - 核心數據的最佳做法」。

+0

我在後臺線程上創建了一個單獨的NSManagedObjectContext並將其指向應用程序的persistentStoreCoordinator。然後在主線程中,我添加了一個通知來偵聽NSManagedObjectContextDidSaveNotification調用,並在主線程的NSManagedObjectContext上調用mergeChangesFromContextDidSaveNotification。不知道它是否是理想的解決方案,但它現在似乎正在變得更好。謝謝你的幫助。 – cullener 2013-03-07 23:34:04

0

獲取你的結果控制器

self.fetchedResultsController = nil; 
+0

我不知道你在哪裏推薦我插入這條語句。我沒有將FetchedResultsController傳遞給解析XML並更新Core Date對象的類。我將該類的ManagedObjectContext設置爲在AppDelegate中創建的ManagedObjectContext。 – cullener 2013-03-07 13:49:48