-1

我意识到这已经被问过很多次了,但我只是不知道我的代码的错误在哪里,抱歉我很愚蠢。

我确实知道错误来自这种方法:

-(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];
}

我在 viewWillAppear 方法中调用该方法...

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

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

谢谢。

4

1 回答 1

3

您在这里遇到了几个问题,主要与在后台线程上修改 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.“get”在 Cocoa 中具有特殊含义)。如果视图多次出现,您可能会导致许多线程同时运行,这当然不是您的意思。

你几乎不应该使用performSelectorInBackground:withObject:. 使用NSOperationQueue或调度队列来管理后台操作。

于 2012-12-11T17:45:04.240 回答