티스토리 뷰

http://nsscreencast.com/episodes/8-automatic-uitableview-paging


프로세스

  1. 현재페이지 = 0 으로 부여.
  2. UITableView가 보여지면서 delegate 중 numberOfRowsInSection 메쏘드 작동.
  3. 현재 페이지가 0이므로 1개의 셀(loadingCell 메쏘드로 만들어지는...) 있다고 리턴.
  4. cellForRowAtIndexPath 메쏘드 작동되며
    현재 indexPath, indexNodes 모두 nil 상태이므로
    loadingCell 메쏘드 작동시켜 activityIndicator가 있는 로딩셀을 만들고 리턴.
  5. 셀이 보여질때 willDisplayCell 메쏘드 호출되는데
    현재 셀이 로딩셀이면 현재페이지+1 하고
    네트워크로부터 데이터 로딩 시작하는 fetchBeers 메쏘드 작동시킴.
    (최초 로딩시는 당연히 로딩셀이므로 do while {} 구문처럼 fetchBeers 메쏘드 작동)
  6. fetchBeers 메쏘드 작동으로
    네트워크로부터 데이터 불러오고 beers 배열에 탑재 후
    UITableView 새로고침.
  7. 2.부터의 과정 반복하는데
    4.의 cellForrowAtIndexPath 메쏘드에서
    beers.count 만큼 UITableViewCell에 데이터를 탑재 후
    그 숫자가 넘어가면 로딩셀을 마지막에 붙임

준비물

http://afnetworking.com
A network framework for iOS & OSX

아래 소스상의 AFJSONRequest~ , AFHTTPRequest~ 들 사용을 위해한건데
대신, HTTP 통신을 위해서라면 NSURLConnection 사용 당연 가능.


선언

#define kLoadingCellTag 1273

NSInteger _currentPage;
NSInteger _totalPages;

NSMutableArray beers;


전체 소스코드

Episode Source Code


Initialization

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.beers = [NSMutableArray array];
    _currentPage = 0;
}

Issue HTTP Request for the current page

- (void)fetchBeers {
    NSString *urlString = [NSString 
      stringWithFormat:@"http://localhost:3000/beers.json?page=%d", 
      _currentPage];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFJSONRequestOperation *operation = 
      [[AFJSONRequestOperation alloc] initWithRequest:request];
    [operation setCompletionBlockWithSuccess:
      ^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"responseObject %@", responseObject);
        
        _totalPages = [[responseObject 
          objectForKey:@"total_pages"] intValue];
        
        for (id beerDictionary in [responseObject 
                                    objectForKey:@"beers"]) {
            Beer *beer = [[Beer alloc] 
              initWithDictionary:beerDictionary];
            if (![self.beers containsObject:beer]) {
                [self.beers addObject:beer];
            }

            [beer release];
        }
        
        [self.tableView reloadData];
        
    } failure:
      ^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error: %@", [error localizedDescription]);
        [[[[UIAlertView alloc] 
          initWithTitle:@"Error fetching beers!"
                message:@"Please try again later"
               delegate:nil
          cancelButtonTitle:@"OK"
          otherButtonTitles:nil] autorelease] show];
    }];
    
    [operation start];
    [operation release];
}

Offset number of rows

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section {
    if (_currentPage == 0) {
        return 1;
    }
    
    if (_currentPage < _totalPages) {
        return self.beers.count + 1;
    }
    return self.beers.count;
}

Render the cells

- (UITableViewCell *)beerCellForIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"cell";
    UITableViewCell *cell = [self.tableView 
dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[[UITableViewCell alloc] 
            initWithStyle:UITableViewCellStyleSubtitle
          reuseIdentifier:cellIdentifier] autorelease];
    }
    
    Beer *beer = [self.beers objectAtIndex:indexPath.row];
    cell.textLabel.text = beer.name;
    cell.detailTextLabel.text = beer.brewery;
    
    return cell;
}

- (UITableViewCell *)loadingCell {
    UITableViewCell *cell = [[[UITableViewCell alloc] 
                 initWithStyle:UITableViewCellStyleDefault
               reuseIdentifier:nil] autorelease];
    
    UIActivityIndicatorView *activityIndicator = 
      [[UIActivityIndicatorView alloc] 
      initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    activityIndicator.center = cell.center;
    [cell addSubview:activityIndicator];
    [activityIndicator release];
    
    [activityIndicator startAnimating];
    
    cell.tag = kLoadingCellTag;
    
    return cell;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row < self.beers.count) {
        return [self beerCellForIndexPath:indexPath];
    } else {
        return [self loadingCell];
    }
}

Fetching the next page

- (void)tableView:(UITableView *)tableView 
  willDisplayCell:(UITableViewCell *)cell 
forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (cell.tag == kLoadingCellTag) {
        _currentPage++;
        [self fetchBeers];
    }


댓글