集合 <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];
}

并在视图中调用该方法将出现方法...

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

任何

提示,我的代码可能有点粗制滥造,非常感谢任何帮助!

谢谢。

这里有几个问题,主要与修改后台线程上的 UI 有关,这是绝对不能做的。例如:

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或调度队列来管理后台操作。

最新更新