0

問題を示すプロジェクトの例: http://d.pr/f/g8x5

iOS で Twitter API と対話するアプリを作成しています (Web API ではなく、ネイティブ OS アクセスを使用)。アイテムを Core Data に送信します。Core Data はUITableViewController、使用する my に表示されますNSFetchedResultsController

私のcellForRowAtIndexPath:メソッドのコードは次のとおりです。

Tweet *tweet = [self.fetchedResultsController objectAtIndexPath:indexPath];

cell.nameLabel.text = tweet.name;
cell.screenNameLabel.text = [NSString stringWithFormat:@"@%@", tweet.screenname];

NSString *tweetText = tweet.text;
tweetText = [tweetText stringByReplacingOccurrencesOfString:@"&" withString:@"&"];

NSMutableAttributedString *tweetAttributedText = [[NSMutableAttributedString alloc] initWithString:tweetText];

// Color @usernames in tweet text for label
NSError *error;
NSRegularExpression *screenNameRegEx = [NSRegularExpression regularExpressionWithPattern:@"\\B@[a-zA-Z0-9_]+" options:0 error:&error];
NSArray *screenNameMatches = [screenNameRegEx matchesInString:tweetText options:0 range:NSMakeRange(0, tweetText.length)];

for (NSTextCheckingResult *match in screenNameMatches) {
    [tweetAttributedText addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:31/255.0 green:121/255.0 blue:189/255.0 alpha:1.0] range:match.range];
}

// Color #hashtags
NSRegularExpression *hashtagRegEx = [NSRegularExpression regularExpressionWithPattern:@"\\B#[a-zA-Z0-9_]+" options:0 error:&error];
NSArray *hashtagMatches = [hashtagRegEx matchesInString:tweetText options:0 range:NSMakeRange(0, tweetText.length)];

for (NSTextCheckingResult *match in hashtagMatches) {
    [tweetAttributedText addAttribute:NSForegroundColorAttributeName value:[UIColor lightGrayColor] range:match.range];
}

// Color links
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
NSArray *linkMatches = [linkDetector matchesInString:tweetText options:0 range:NSMakeRange(0, tweetText.length)];

for (NSTextCheckingResult *match in linkMatches) {
    // Make sure it's not a telephone number link
    if (![match.URL.scheme isEqualToString:@"tel"]) {
        [tweetAttributedText addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:21/255.0 green:116/255.0 blue:255/255.0 alpha:1.0] range:match.range];
    }
}

cell.tweetTextLabel.attributedText = tweetAttributedText;

return cell;

次に、viewDidAppear で Twitter API を呼び出し、新しい記事をプルダウンします。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    self.accountStore = [[ACAccountStore alloc] init];

    // If user has logged into Twitter system-wide
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
        ACAccountType *twitterAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

        [self.accountStore requestAccessToAccountsWithType:twitterAccountType options:nil completion:^(BOOL granted, NSError *error) {
            if (granted) {
                NSArray *twitterAccounts = [self.accountStore accountsWithAccountType:twitterAccountType];
                NSURL *requestURL = [NSURL URLWithString:@"https://api.twitter.com"
                                     @"/1.1/statuses/home_timeline.json"];
                NSDictionary *requestParameters = @{@"include_rts": @"0",
                                                    @"count": @"20"};

                SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:requestParameters];
                request.account = twitterAccounts[0];

                [request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                    if (responseData) {
                        if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
                            NSError *jsonError;
                            NSArray *homeTimelineData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&jsonError];

                            for (NSDictionary *tweetDictionary in homeTimelineData) {
                                NSManagedObjectContext *context = self.managedObjectContext;

                                Tweet *tweet = [NSEntityDescription insertNewObjectForEntityForName:@"Tweet" inManagedObjectContext:context];
                                tweet.text = [tweetDictionary objectForKey:@"text"];
                                tweet.name = [[tweetDictionary objectForKey:@"user"] objectForKey:@"name"];
                                tweet.screenname = [[tweetDictionary objectForKey:@"user"] objectForKey:@"screen_name"];

                                // Save the date of when the tweet was posted
                                NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                                dateFormatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
                                tweet.date = [dateFormatter dateFromString:[tweetDictionary objectForKey:@"created_at"]];

                                NSError *error;
                                if (![context save:&error]) {
                                    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                                }
                            }
                        }
                    }
                }];
            }
            else {

            }
        }];
    }
    // If not logged in system-wide, alert user to log in via Settings
    else {
        UIAlertView *notLoggedInAlert = [[UIAlertView alloc] initWithTitle:@"Not Logged in to Twitter" message:@"You must be logged into Twitter. Go to the Settings app and log in from there." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];

        [notLoggedInAlert show];
    }
}

しかし、個々のセルをタップするまで実際にはアイテムは表示されず、そのセルのみが表示されます。メインスレッドが更新されていない問題のように感じますが、何が起こっているのかわかりません。

私は正確に何を間違っていますか?

4

2 に答える 2

1

In looking at it again, the SLRequest callback is being made on a background thread which prevents CoreData and UIKit from functioning properly. Wrap the entire block in:

dispatch_async(dispatch_get_main_queue(), ^{
    if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
    ...
    }
});
于 2014-03-12T21:09:27.597 に答える