-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 に答える