2013-03-07 34 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