集合在枚举时发生了变化

问题描述:

我意识到这已被问了很多次,但我只是不知道错误在哪里出现在我的代码中,对于愚蠢而抱歉。集合<CALayerArray:0x1cdb9b90>在枚举时发生了变化

我知道故障是由这种方法:

-(void)getDataFromDatabase { 
    UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 
    indicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0); 
    indicator.center = self.view.center; 
    [indicator bringSubviewToFront:self.view]; 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE; 
    [indicator startAnimating]; 

    CGRect screenRect = [[UIScreen mainScreen] bounds]; 

    UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; 

    overlay.backgroundColor = [UIColor whiteColor]; 

    [self.view addSubview:overlay]; 
    [self.view addSubview:indicator]; 

    NSString *listingurl; 

    listingurl = [NSString stringWithFormat:@"http://www.herefordshire-tourism-guide.co.uk/app/query.php?getlisting=1&listingname=%@", rowSelectedName]; 

    listingurl = [listingurl stringByReplacingOccurrencesOfString:@" " withString:@"%20"]; 

    NSURL *url = [NSURL URLWithString:listingurl]; 

    NSError *error = nil; 
    NSStringEncoding encoding; 

    NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url usedEncoding:&encoding 
                  error:&error]; 

    NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding]; 

    // In "real" code you should surround this with try and catch 
    NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error]; 
    if (dict) 
    { 
     rows = dict[@"listings"]; 
    } 
    dict = rows[0]; 

    self.photos.font = [UIFont fontWithName:@"ProximaNova-Regular" size:18.0]; 
    self.likes.font = [UIFont fontWithName:@"ProximaNova-Regular" size:18.0]; 
    self.businessName.font = [UIFont fontWithName:@"ProximaNova-Extrabld" size:20.0]; 
    self.address.font = [UIFont fontWithName:@"ProximaNova-Regular" size:16.0]; 

    self.navigationItem.title = dict[@"business"]; 

    NSString *favdb = [NSString stringWithFormat:@"%@", dict[@"favs"]]; 

    if ([favdb isEqualToString:@""]) { 
     NSString *fav = [NSString stringWithFormat:@"0 Likes"]; 
     self.favourites.text = fav; 
    } else { 
     NSString *fav = [NSString stringWithFormat:@"%@ Likes", dict[@"favs"]]; 
     self.favourites.text = fav; 
    } 

    if ([favdb isEqualToString:@"1"]) { 
     NSString *fav = [NSString stringWithFormat:@"1 Like"]; 
     self.favourites.text = fav; 
    } 

    self.businessName.text = dict[@"business"]; 
    self.address.text = dict[@"location"]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 
              (unsigned long)NULL), ^(void) { 

     UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 
     indicator.frame = CGRectMake(140, 85, 40.0, 40.0); 
     [indicator bringSubviewToFront:self.view]; 
     [indicator startAnimating]; 
     [self.view addSubview:indicator]; 

     UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:dict[@"image1"]]]]; 

     self.image.image = img; 

     [UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE; 
     [indicator stopAnimating]; 
    }); 

    listingLoc = [[CLLocation alloc] initWithLatitude:[dict[@"lat"] doubleValue] longitude:[dict[@"lon"] doubleValue]]; 

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 

    float kilometers = [appDelegate.currentLoc distanceFromLocation:listingLoc]/1000; 

    int milesint = kilometers * 0.621371192; 

    NSString *milesOut = [NSString stringWithFormat:@"%i miles", milesint]; 

    self.distance.text = milesOut; 

    networkImages = [[NSMutableArray alloc] init]; 

    if (dict[@"image1"] != @"") { 
     [networkImages addObject:dict[@"image1"]]; 
    } 

    [indicator stopAnimating]; 
    [overlay removeFromSuperview]; 
} 

和IM呼吁在viewWillAppear中方法的方法...

[self performSelectorInBackground:@selector(getDataFromDatabase) withObject:nil];

任何提示,我的代码可能是以次充好,任何帮助都非常感谢!

谢谢。

+1

这是很多代码。你在哪里迭代数组元素? –

+1

好吧,无论何时你使用UIKit方法进行交互(如上面添加和删除子视图),它必须在主线程上完成,而不是在后台线程中完成,就像你在这里做的那样。 UIKit是**不是线程安全的! – lnafziger

你在这里有几个问题,主要涉及修改后台线程上的用户界面,你绝对不能这样做。例如:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 
             (unsigned long)NULL), ^(void) { 

    UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 
    indicator.frame = CGRectMake(140, 85, 40.0, 40.0); 
    [indicator bringSubviewToFront:self.view]; 
    [indicator startAnimating]; 
    [self.view addSubview:indicator]; 
    ... 

在这里,我们修改后台线程当前视图的子视图列表。这不合法。大多数UIKit方法必须在主线程上运行(从GCD的角度来看,这是主队列)。

这条线也是极其危险的内部viewWillAppear:(或大多数的任何地方):

[self performSelectorInBackground:@selector(getDataFromDatabase) withObject:nil]; 

你的看法可能出现,并在getDataFromDatabase消失多次(旁注:你应该把这个fetchDataFromDatabase“搞定”了可可中的特殊含义)。如果视图出现多次,你可以结束许多线程同时运行,这当然不是你的意思。

你应该几乎从不使用performSelectorInBackground:withObject:。使用NSOperationQueue或分派队列来管理后台操作。

+0

我刚开始学习,太复杂了!你可以给我一些代码示例,这样我就可以玩了! – rjg

+0

还没有线索从哪里开始! – rjg

+0

我会开始简单。我在上面的代码中看不到任何需要后台线程的东西。您可以在不产生线程的情况下进行大量的iOS开发。您的主要问题是您已将JSON网络提取集成到视图控制器中。不要这样做。将数据提取放入只管理数据的模型类中(并使用NSURLConnection异步获取数据)。然后视图控制器将响应模型类的变化。请参阅http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MVC.html –