2014-03-12 4 views
0

예 프로젝트 보여주는 문제 :http://d.pr/f/g8x5왜 앱을로드 한 후에 핵심 데이터에 항목을 추가 할 때 셀을 탭할 때까지 항목이 표시되지 않습니까? (만 하나를 보여줍니다.)

내가 (아닌 웹 API를 통해 네이티브 OS 액세스를 사용) iOS의 트위터 API와 상호 작용하는 응용 프로그램을 짓고 있어요. 항목을 핵심 데이터로 보내면 내 UITableViewController에 표시되어야하며 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:@"\\[email protected][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에 나는 새로운 기사를 트위터 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]; 
    } 
} 

그러나 항목 중 어느 것도 실제로 표시하지 각 개별 셀을 탭할 때까지 만 표시되면이 표시됩니다. 나에게 그것이 메인 스레드가 업데이트되지 않는 문제인 것처럼 느낀다. 그러나 나는 무슨 일이 일어나는지 전혀 모른다.

내가 뭘 잘못하고 있니?

+0

레이블의 프레임은 무엇입니까? 셀을 두드려서 셀의 내용을 레이아웃합니까? 어떤 디버깅을 했습니까? – Wain

+0

'NSFetchedResultsControllerDelegate'를'UITableView', https://developer.apple.com/library/ios/DOCUMENTATION/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html#//apple_ref/doc/uid로 올바르게 구현 했습니까?/TP40008227-CH1-SW26? – Rich

+0

Xcode에서 제공하는 핵심 데이터를 사용하여 마스터 세부 템플릿의 구현을 복사했습니다. –

답변

0

NSFetchedArrayController 대리자 메서드를 구현하고 자신을 가져 오기 컨트롤러의 대리자로 설정해야합니다. 그렇게하면 가져온 내용이 변경 될 때 변경 사항에 대한 알림을 받게됩니다.

+0

@Doug Smith 다음은 [documentation]입니다 (https://developer.apple.com/library/ios/DOCUMENTATION/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40008227-CH1- SW26)을 참고하십시오. – Rich

+0

저는 실제로 자신을 위임자로 설정합니다 (첨부 된 프로젝트 참조). NSFetchedResultsController가 아니라 NSFetchedArrayController라고 가정합니다. –

+0

예, 실제로 NSFetchedResultsController를 의미합니까, 위임 메서드를 구현합니까? 특히 controllerWillChangeContent : controllerDidChangeContent : 및 컨트롤러 : didChangeSection : atIndex : forChangeType :? 처음 두 개만 제공하면 무차별 적으로 수행 할 수 있지만 세 개 모두 제공하면 더 나은 시각적 결과를 얻을 수 있습니다. Apple docs에 대해서는 https://developer.apple.com/library/ios/DOCUMENTATION/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intf/NSFetchedResultsControllerDelegate –

1

다시 한번 살펴보면 CoreData와 UIKit이 제대로 작동하지 못하게하는 백그라운드 스레드에서 SLRequest 콜백이 수행되고 있습니다. 전체 블록을 다음으로 묶으십시오.

dispatch_async(dispatch_get_main_queue(), ^{ 
    if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) { 
    ... 
    } 
}); 
+0

아 하, 좋은 눈. –

+0

하지만 그때 나는 주 스레드를 차단합니다. 주 스레드를 차단할 수 없지만 완료되면 주 스레드를 업데이트 할 수있는 방법을 어떻게 조합합니까? –

+0

백그라운드 스레드에서 사용하기 위해 별도의 ModelObjectManager를 생성하고 데이터 파싱이 실제로 중요하다면 결과를 병합 처리 할 수 ​​있습니다.백그라운드 스레드에서 CoreData를 사용하는 방법에 대한 자세한 내용은 Apple 문서를 확인해야합니다. 명확히하기 위해, 메인 쓰레드에서 네트워크 연산 (긴 부분)을 수행하지 않고, 응답을 파싱하는 것입니다. 또 다른 옵션은 백그라운드 스레드의 응답을 구문 분석하고 일종의 중간 결과 (NSArray의 NSArray)를 포 그라운드로 보냅니다. –