서버에 이미지를 요청하여 화면에 뿌려주는 작업을 진행 중에 UITableView와 NSURLConnection의 동기화 문제로 고민하게 되었다

테이블뷰가 스크롤과 네트워크 작업은 서로 메인 Thread에서 진행되기 때문이다.

원하는 결과는 스크롤을 하면서도 화면에 출력될때 이미지를 받아올수 있어야 하기 때문에 인터넷을 찾아본 결과 의외로 간단했다

해답은 NSRunLoop의 설정을 변경해주어야 했었다.

아래 일반적으로 사용하는 NSURLConnection이다.

NSURLConnection * mConnection = [[NSURLConnection alloc] initWithRequest:aRequest delegate:self startImmediately:NO];
self.connection = mConnection;
[mConnection release];

[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.connection start];

위에서 보면 connection에 ScheduleInRunLoop:forMode: 메소드를 통해 현재 RunLoop에 Connection을 등록하는 부분이 있다.

여기서 Mode를 보면 NSDefaultRunLoopMode인데 이 부분이 중요했다.

우선 RunLoop에 connection을 연결하면 네트워크 요청 후 응답때까지 RunLoop에서 대기하는 용도로 사용한다. 보통 Opreation이나 Thread같은 경우

main이 실행되고 나면 역활이 끝나기 때문에 비동기적으로 대기하고 있으려면 저렇게 RunLoop에 등록해 두어야 한다.

하지만 기본적으로 사용하는 NSDefaultRunLoopMode을 사용하게 되면 테이블 스크롤 이벤트와 우선순위에서 낮아서 그런지 몰라도 UI Event가 우선 실행되고 Connection응답이 나중에 처리 된다.

이 현상을 수정하기 위해 Mode의 값을 변경하였다.

NSDefaultRunLoopMode -> NSRunLoopCommonModes

RunLoop 모드가 딱 두가지 밖에 없으므로 찾기에 어렵지 않을 것이다.

마지막으로 connection이 종료 후 작업을 마무리할때는 connection을 RunLoop스케줄에서 해제를 해주어야 한다.

[self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

UITableView를 사용하다 보면 테이블을 Section별로 나눠 사용해야 할 필요가있다.

테이블 타입이 Group이 아닌 Plain타입일 경우 Section의 타이틀을 지정할 경우 스크롤시 헤더가 고정되는 현상을 일으킨다.

하지만 고정이 아닌 스크롤과 동시에 사라지게 하기 위해서는 다음과 같은 코드를 추가하면 해결할수 있다.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
   
    // 각 세션의 헤더가 스크롤시 고정되있는 현상을 수정하기 위해 위치를 재조정하는 코드 추가
    CGFloat sectionHeaderHeight = self.tableView.sectionHeaderHeight;
    if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
        scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
    } else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
    }
}

테이블뷰는 UIScrollView를 상속받아 구현되어있기 때문에 위와 같은 메소드를 오버라이드해서 구현이 가능하다.

위 코드를 삽입하게 되면 Section의 고정현상이 사라지게 된다.

추가로 Footer뷰를 사용하기 위해서는 아래와 같은 방식을 적용하였다.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
   
    CGFloat footerHeight = self.clearAllView.bounds.size.height;
   
    CGFloat height = scrollView.frame.size.height;
   
    CGFloat contentYoffset = scrollView.contentOffset.y;
   
    CGFloat distanceFromBottom = scrollView.contentSize.height - contentYoffset - footerHeight;
   
    if(distanceFromBottom < height )
    {
        CGFloat diff =  footerHeight - (height - distanceFromBottom);
        if(diff >= 0 && diff <= footerHeight){
            scrollView.contentInset = UIEdgeInsetsMake(0, 0, -diff, 0);
        }
    }else{
       
        scrollView.contentInset = UIEdgeInsetsMake(0, 0, -footerHeight, 0);
    }
}

+ Recent posts