2010-02-13 1 views
10

전자 메일 주소를 포함하여 웹 API에서 데이터를 가져 오는 iPhone 응용 프로그램을 만들고 있습니다. 테이블 셀에있는 각 이메일 주소와 연결된 이미지를 표시하고 싶습니다. 따라서 주소록에서 이미지를 검색하고 전자 메일 주소가 책에 없으면 기본값으로 되돌아갑니다. 이 잘 작동하지만 몇 가지 문제가 있습니다iPhone에서 비동기 이미지 캐싱에 대한 최선의 방법은 무엇입니까?

  • 성능 : 나는 이메일 주소 (또는 전화 번호)에 의해 주소록 레코드에 대해보고를 위해 찾은 조리법 rather slow 보도됩니다. 그 이유는 모든 주소록 레코드를 반복해야하며 이미지가있는 각 레코드에 대해 모든 전자 메일 주소를 반복하여 일치하는 것을 찾습니다. 물론 큰 주소록의 경우 시간이 많이 걸릴 수 있습니다.

  • 테이블 셀 : 그래서 이미지를 찾고 모든 것을 한 번에 찾아야하는 모든 이메일 주소를 수집 할 것이라고 생각했습니다. 이렇게하면 모든 주소에 대해 한 번만 책을 반복합니다. 그러나 이것은 각 셀이 하나의 전자 메일 주소에 해당하는 테이블 셀에는 적합하지 않습니다. 나는 어떤 세포 (잠재적으로 천천히)를 표시하기 전에 모든 이미지를 모으거나 각 세포가로드 될 때 각 이미지를 찾도록해야한다. (더 느리다. 에 대한 일치를 찾기 위해 책을 반복 할 필요가있다. 각 이메일 주소).

  • 비동기 조회 : 그래서 나는 그들을 일괄 적으로 보았을 것이라고 생각했지만, 비동기 적으로는 NSInvocationOperation을 사용했습니다. AddressBook에있는 각 이미지에 대해 앱 샌드 박스에 미리보기 이미지를 저장합니다. 그런 다음 각 셀은이 파일을 참조하고 존재하지 않는 경우 기본값을 표시 할 수 있습니다 (책에 없거나 아직 찾지 못했기 때문에). 나중에 이미지가 비동기 조회에서 발견되면 다음에 이미지를 표시해야 할 때 갑자기 나타납니다. 이는 이미지를 주기적으로 재생할 때 (예 : 주소록에서 이미지가 변경된 경우) 잘 작동합니다. 하지만 내 애플 리케이션의 특정 인스턴스에 대한 이미지가 실제로 잠시 동안 표시되지 않을 수 있습니다.

  • 비동기 표 셀 조회 : 이상적으로, 나는 그것을 다운로드 한 후 이미지와 테이블 셀을 업데이트 markjnet's asynchronous table cell updating 같은 것을 사용하십시오. 그러나이 작업을하려면 각 셀이 표시된대로 캐시 된 아이콘이 샌드 박스에없는 경우 NSInvocationOperation 작업을 스핀 (spin off)해야합니다. 그러나 각 주소록 전체를 비효율적으로 반복하는 방법으로 돌아 왔고 방금 새로운 이메일 주소를 다 다운로드 한 경우 많은 메일을 보낼 수 있습니다.

그럼 내 질문은 : 다른 사람들이 어떻게합니까? 나는 Tweetie2를 만지작 거리며 테이블 셀을 비동기 적으로 업데이트하는 것처럼 보입니다. 필요로하는 모든 이미지에 대해 별도의 HTTP 요청을 보내는 것으로 가정합니다. 그렇다면 이메일 주소로 로컬 주소록을 검색하는 것이 덜 효율적이지 않으므로 최선의 방법이라고 생각합니다. 주소록 검색과 관련된 성능 문제는 걱정하지 않으셔도됩니다.

그렇다면 캐싱에 대한 최선의 방법은 샌드 박스에 미리보기 이미지를 저장하는 것입니까? 그리고 주소록의 모든 변경 사항으로 모든 축소판을 업데이트하기 위해 새로운 일자리를 만들고 싶다면 하루에 한 번씩 이렇게 말하기에 가장 좋은 방법은 무엇일까요?

나머지는 어떻게 이런 종류의 문제를 해결합니까? 제안을 많이 부탁드립니다!

답변

2

을에 관계없이 이미지의 실제 캐싱에 사용하는 것을 전략의, 나는 단지 주소록 데이터를 통해 당신이 얻을 때마다 하나의 패스를 만들 것 가능한 경우 이메일 주소의 일괄 처리. (그리고 네, 비동기 적으로 이것을 할 것입니다.)

검색 결과를위한 메모리 캐시로 사용할 NSMutableDictionary를 만듭니다. 다운로드 한 각 이메일 주소를 키로 사용하여이 사전을 초기화하고 해당 키 값으로 센티널을 지정하십시오 (예 : [NSNull null]).

다음으로 주소록의 각 ABRecordRef를 반복하고 ABRecordCopyValue(record, kABPersonEmailProperty)을 호출하고 반환되는 각 ABMultiValue의 결과를 반복합니다. 전자 메일 주소 중 하나가 캐시의 키인 경우 [NSNumber numberWithInt:ABRecordGetRecordId(record)]을 사전의 해당 키 값으로 설정하십시오.

이 사전을 조회 색인으로 사용하면 사용자의 현재 스크롤 위치에 따라 테이블보기에 현재 표시되어있는 전자 메일 주소에 대해서만 ABRecordRefs의 이미지를 빠르게 얻을 수 있습니다 (hoopjones의 답변에 나와 있음). 주소록 변경 수신기를 추가하여 캐시를 무효화하고 다른 인덱싱 작업을 트리거 한 다음 응용 프로그램에 "최신 상태"수준이 필요한 경우보기를 업데이트 할 수 있습니다.

+0

감사합니다. 그래서 한 번에 하나의 주소를 찾는 솔루션을 실제로 구현했지만, 미리보기 이미지를 만들어 샌드 박스 문서 디렉토리에 저장합니다. 그리고 네, 그것은 그들이 처음으로 표시해야 할 때 주소록의 이미지를 찾습니다.캐시 된 이미지를 샌드 박스에서로드하는 것이 비동기 일 필요는 없다는 것을 충분히 빨리 생각해야합니다. 당신이 설명하는 최신 수준을 필요로하지 않으므로 캐시 된 미리보기 이미지의 정기적 인 업데이트를 예약하는 방법을 살펴 보겠습니다. 예, 주소록을 통해서만 반복합니다. 모두를 위해 한 번. – theory

+0

궁금한 점, 한 번에 하나의 주소를 검색 할 수는 있지만 주소록을 한 번만 반복하면됩니까? – erikprice

2

나열된 마지막 방법 (비동기 테이블 셀 조회)을 사용하지만 표시되는 현재 레코드의 이미지 만 봅니다.사용자가 스크롤을 멈 추었을 때 알아 내기 위해 UIScrollViewDelegate 메소드를 오버로드 한 다음 현재 보이는 셀에 대한 요청 만 시작합니다.

이런 식으로 뭔가 (내가 지금 찾을 수없는이 약간 나는 웹에서 볼 수있는 튜토리얼에서 수정, 사과는 저자 인용하지 않는) :

- (void)loadContentForVisibleCells 
{ 
    NSArray *cells = [self.table visibleCells]; 
    [cells retain]; 
    for (int i = 0; i < [cells count]; i++) 
    { 
     // Go through each cell in the array and call its loadContent method if it responds to it. 
     AddressRecordTableCell *addressTableCell = (AddressRecordTableCell *)[[cells objectAtIndex: i] retain]; 
     [addressTableCell loadImage]; 
     [addressTableCell release]; 
     addressTableCell = nil; 
    } 
    [cells release]; 
} 


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 
{ 
    // Method is called when the decelerating comes to a stop. 
    // Pass visible cells to the cell loading function. If possible change 
    // scrollView to a pointer to your table cell to avoid compiler warnings 
    [self loadContentForVisibleCells]; 
} 


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 
{ 
    if (!decelerate) 
    { 
     [self loadContentForVisibleCells]; 
    } 
} 

을 당신은 무엇 주소 기록이 알게되면 현재 볼 수있는 것, 아마 그 (5 - 7 기록 아마도)에 대한 검색을 번개 빠른 것입니다. 이미지를 가져온 후에는 사전에 캐시하여 나중에 이미지 요청을 다시 할 필요가 없습니다.

+0

을 관리, 왜이 샘플 코드의 NSArray를 유지 않습니다 셀, 그리고 각각의 AddressRecordTableCell을 사용하기 전에 'loadContentForVisibleCells'에서 그것들을 처리 한 다음 해제해야합니다. 나는 그 메소드를 실행하는 동안 그들이 dealloc 될 수있는 것을 볼 수 없다. – erikprice

+2

맞습니다. 그것은 유지 될 필요가 없습니다. 나는 코코아를 배웠을 때이 코드를 다시 작성 했으므로 몇 가지 멍청함이있다. :) – hoopjones

+0

['UIScrollViewDelegate'] (http://developer.apple.com/iphone/library/documentation/)에 대해 잘 알고있다. UIKit/참조/UIScrollViewDelegate_Protocol/참조/UIScrollViewDelegate.html). 그것은 아래의 yonel로 링크 된 [LazyTableImages 예제] (http://developer.apple.com/iphone/library/samplecode/LazyTableImages/index.html)도 사용합니다. 재미있는 점은 Tweetie 2는이 방법을 사용하지 않는 것입니다. 빨리 스크롤하면 이미지가 스크롤되는 동안 이미지가로드됩니다. 스크롤하는 동안 애플 앱이 이미지를로드하지 않는다고 항상 괴롭 혔고 Tweetie 2는 필요하지 않다는 것을 보여줍니다. – theory

1

UITableView에서로드하는 게으른 이미지를 구현하려고하는 것 같습니다. 애플의 좋은 예 거기, 내가 여기를 참조하고 있습니다 : Lazy load images in UITableView

+0

'LazyTableImages' 예제에 대한 링크에 대해 많은 감사를드립니다. 나는 그것을 인식하지 못했으며, 공부하게되어 기뻤습니다. – theory

관련 문제