Nib에서 재사용 가능한 UITableViewCell로드


89

사용자 지정 UITableViewCell을 디자인하고 http://forums.macrumors.com/showthread.php?t=545061 에있는 스레드에 설명 된 기술을 사용하여 잘로드 할 수 있습니다 . 그러나 해당 메서드를 사용하면 더 이상 재사용 식별자로 셀을 초기화 할 수 없습니다. 즉, 호출 할 때마다 각 셀의 완전히 새로운 인스턴스를 만들어야합니다. 누군가 재사용을 위해 특정 셀 유형을 캐시하는 좋은 방법을 알아 냈지만 여전히 Interface Builder에서 설계 할 수 있습니까?

답변:


74

적절한 메서드 서명을 사용하여 메서드를 구현하기 만하면됩니다.

- (NSString *) reuseIdentifier {
  return @"myIdentifier";
}

이 방법을 어디에서 구현합니까?
Krishnan


5
이것은 위험합니다. 셀 하위 클래스의 두 개의 하위 클래스가 있고이 두 가지를 단일 테이블보기에서 사용하면 어떻게됩니까? 재사용 식별자 호출을 super에 보내면 잘못된 유형의 셀을 대기열에서 빼게됩니다 .............. reuseIdentifier 메서드를 재정의해야한다고 생각하지만 대체 식별자를 반환해야합니다. 끈.
SK9

3
고유한지 확인하려면 다음을 수행하십시오.return NSStringFromClass([self class]);
ivanzoid

119

실제로 Interface Builder에서 셀을 빌드하고 있으므로 재사용 식별자를 설정하십시오.

IB_reuse_identifier

또는 Xcode 4를 실행중인 경우 Attributes inspector 탭을 확인하십시오.

여기에 이미지 설명 입력

(편집 : XIB가 XCode에 의해 생성 된 후 빈 UIView가 포함되어 있지만 UITableViewCell이 필요하므로 UIView를 수동으로 제거하고 Table View Cell을 삽입해야합니다. 물론 IB는 a에 대한 UITableViewCell 매개 변수를 표시하지 않습니다. UIView.)


하나 이상의 셀에 대해이 Nib 생성 셀을 사용하는 경우 식별자를 어떻게 설정합니까? 이것은 동일한 식별자를 가진 두 개의 셀을 갖도록 유도합니다.
Krishnan

4
고유 한 식별자로 생각하지 말고 형식 이름과 비슷하게 생각하십시오.
Tim Keating

Xcode 4.3.3의 내장 인터페이스 빌더를 통해 식별자를 설정하는 옵션이 표시되지 않습니다. 확실히 클래스를 UITableViewCell 하위 클래스로 설정하고 있습니다. 그냥 놓치고 있습니까, 아니면 사라 졌습니까?
Tyler

3
네, 문제를 해결했습니다. 인터페이스 빌더 (Xcode 4 내)에서 UIView 객체로 시작하고 해당 클래스를 UITableViewCell로 변경하면 재사용 식별자와 같은 셀 관련 속성을 얻지 못합니다. 이를 얻으려면 빈 xib로 시작하고 테이블 셀 개체를 드래그하면 편집 할 수있는 셀 관련 속성이 있습니다.
Tyler

1
@Krishnan 이렇게 생각해보세요. 식별자 X가있는 테이블 뷰 셀을 만들면 "X 레이블이 붙은 풀에서 셀을주세요."라고 말하는 것입니다. 풀이 있고 거기에 사용 가능한 셀이 있으면이를 제공합니다. 그렇지 않으면 풀 (필요한 경우)을 생성 한 다음 셀에 뉴스를 올리고 "X"라고 표시 한 다음 사용자에게 전달합니다. 따라서 셀은 고유 할 수 있습니다. 예를 들어 특정 식별자가있는 하나의 셀로만 풀을 만들 수 있지만 라이브러리는 메모리 할당 / 해제를 피하기 위해 무료 목록과 같은 전략을 사용합니다.
Tim Keating

66

이제 iOS 5에는 적절한 UITableView 메서드가 있습니다.

- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier

10
수락 된 답변을 포함하여이 스레드의 다른 답변에는 오래된 조언이 포함되어 있습니다.
Kaelin Colclasure 2012

이 이전 버전과 호환됩니까? 예를 들어 SDK 5.0으로 앱을 개발하고 최소 4.0을 목표로하면 iOS 4.0이 설치된 기기에서 앱이 실행됩니까?
Abolfoooud

1
아니요, iOS 5.0의 새로운 API와 마찬가지로 이전 버전과 호환되지 않습니다.
marzapower 2013 년

: 컨트롤러에이를 통합하는 방법의 가공 한 예를 mindfiresolutions.com/...
mblackwell8

47

이 코드를 처음 어디에서 찾았는지 기억할 수 없지만 지금까지 잘 작동하고 있습니다.

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"CustomTableCell";
    static NSString *CellNib = @"CustomTableCellView";

    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellNib owner:self options:nil];
        cell = (UITableViewCell *)[nib objectAtIndex:0];
    }

    // perform additional custom work...

    return cell;
}

Interface Builder 설정 예 ...

대체 텍스트


12

이 질문에 대한 답을보십시오.

Interface Builder에서 NSCell 서브 클래스를 디자인 할 수 있습니까?

IB에서 UITableViewCell을 디자인 할 수있을뿐만 아니라, 그렇지 않으면 모든 수동 배선 및 여러 요소의 배치가 매우 지루하기 때문에 바람직합니다. 가능한 경우 모든 요소를 ​​불투명하게 만들도록주의하는 한 성능은 괜찮습니다. 재사용 ID는 UITableViewCell의 속성에 대해 IB에서 설정되며, 대기열에서 빼려고 할 때 코드에서 일치하는 재사용 ID를 사용합니다.

또한 작년에 WWDC의 일부 발표자로부터 IB에서 테이블 뷰 셀을 만들면 안된다는 말을 들었습니다.


2
투명성이 필요하고 우수한 스크롤 성능을 원한다면 IB에서 테이블 뷰 셀을 만들지 마십시오. 특정 UI의 경우 투명성이 필요합니다 (예 : 그래픽 위에 텍스트를 렌더링하기 위해). 때로는 오래된 (A4 이전) 하드웨어에서 좋은 스크롤을 달성하는 유일한 방법은 GPU가 여러 투명 레이어를 합성해야하는 것을 피하기 위해 코드로 렌더링하는 것입니다.
Nick Forge

2
사실이지만 IB에 내장 된 셀의 유지 보수 용이성을 위해 오래된 장치에서 성능이 약간 저하되도록하는 것이 더 나을 수 있습니다. 이 기술을 사용자 정의 그리기 방법으로 합성하는 것을 방지하기 위해 요소를 그리는 템플릿 셀로 사용할 수도 있습니다.
Kendall Helmstetter Gelner


6

다음은 또 다른 옵션입니다.

NSString * cellId = @"reuseCell";  
//...
NSArray * nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomTableCell" owner:nil options:nil];

for (id obj in nibObjects)
{
    if ([obj isKindOfClass:[CustomTableCell class]])
    {
        cell = obj;
        [cell setValue:cellId forKey:@"reuseIdentifier"];
        break;
    }
}

이것은에 UITableViewCell대한 고유 값을 설정하기 위해 사용자 지정 을 하위 클래스화할 필요가없는 유일한 솔루션 입니다 reuseIdentifer. 나는 이것이 원래의 작전이 실제로 찾고 있던 것이라고 생각합니다.
charshep

나는 애플이 이것을 사용하는 나의 응용 프로그램을 거부하지 않기를 바란다. 나는 이것을 "정적"세포를 얻기 위해 사용하고있다. 내 테이블보기에서 세포를 채우는 과정이 조용하기 때문이다. 이렇게하면 한 번만 실행하면됩니다 (각 행에 다른 식별자를 부여). 감사합니다!
Ricard Pérez del Campo

이것을 수동으로 설정하는 UITableViewCell 메소드가 없기 때문에 매우 유용합니다!
Jesse

2

비슷한 방식으로 사용자 지정 뷰 셀을 만듭니다. 단 IBOutlet을 통해 셀을 연결합니다.

그만큼 [nib objectAt...] 접근 방식은 배열에서 항목의 위치가 변경되기 쉽습니다.

그만큼 UIViewController단지 그것을 시도, 그것은 좋은 충분히 작동 - 방법이 좋다.

그러나...

모든 경우에 initWithStyle 생성자가 호출되지 않으므로 기본 초기화가 수행되지 않습니다.

내가 사용에 대한 다양한 장소를 읽고 initWithCoderawakeFromNib 지만 둘 중 하나가 올바른 방법이라는 결정적인 증거는 없습니다.

메서드에서 일부 초기화 메서드를 명시 적으로 호출하는 것 외에는 cellForRowAtIndexPath아직 이에 대한 답을 찾지 못했습니다.


awakeFromNib는 NIB에서로드되는 객체에 반응하는 올바른 방법입니다.
Jon Hess

2

얼마 전 blog.atebits.com 에서이 주제에 대한 훌륭한 블로그 게시물을 찾았고 , 이후 모든 UITableViewCell을 수행하기 위해 Loren Brichter ABTableViewCell 클래스를 사용하기 시작했습니다.

모든 위젯을 넣을 수있는 간단한 컨테이너 UIView로 끝나고 스크롤이 매우 빠릅니다.

이것이 유용하기를 바랍니다.


2

이 기술은 또한 작동하며 메모리 관리를 위해 뷰 컨트롤러에 펑키 한 ivar가 필요하지 않습니다. 여기서 사용자 정의 테이블보기 셀은 "CustomCell.xib"라는 xib에 있습니다.

 static NSData *sLoadedCustomCell = nil;

 cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
 if (cell == nil) 
 {
   if (sLoadedCustomCell == nil) 
   {        
      // Load the custom table cell xib
      // and extract a reference to the cell object returned
      // and cache it in a static to avoid reloading the nib again.

      for (id loadedObject in [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil]) 
      {
        if ([loadedObject isKindOfClass:[UITableViewCell class]]) 
        {
          sLoadedCustomCell = [[NSKeyedArchiver archivedDataWithRootObject: loadedObject] retain];
          break;
        }
    }
    cell = (UITableViewCell *)[NSKeyedUnarchiver unarchiveObjectWithData: sLoadedCustomCell];
  }

1
보관 및 보관 취소는 완전히 불필요합니다.
Bryan Henry

1
대기열에서 빼낼 수 없을 때마다 펜촉에서 셀을로드해도 괜찮다면 보관 / 보관 취소가 필요하지 않습니다. 그러나 nib에서 정확히 한 번만 셀을로드하려면 메모리에 캐시해야합니다. UITableViewCell이 NSCopying을 구현하지 않기 때문에 NSKeyedArchiving을 사용하여 캐싱을 수행합니다.
Bill Garrison

1
즉, UINib를 사용하여 셀을로드하면 동일한 효과를 얻을 수 있습니다. 디스크에서 한 번로드하고 이후에는 메모리에서로드합니다.
Bill Garrison

2

루이 방법이 나를 위해 일했습니다. 이것은 펜촉에서 UITableViewCell을 만드는 데 사용하는 코드입니다.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellId"];

    if (cell == nil) 
    {
        UIViewController *c = [[UIViewController alloc] initWithNibName:@"CustomCell" bundle:nil];
        cell = (PostCell *)c.view;
        [c release];
    }

    return cell;
}

2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *simpleTableIdentifier = @"CustomCell";

CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
    cell = [nib objectAtIndex:0];

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}         

return cell;
}

1

gustavogb 솔루션이 나를 위해 작동하지 않습니다. 내가 시도한 것은 다음과 같습니다.

ChainesController *c = [[ChainesController alloc] initWithNibName:@"ChainesController" bundle:nil];
[[NSBundle mainBundle] loadNibNamed:@"ChaineArticleCell" owner:c options:nil];
cell = [c.blogTableViewCell retain];
[c release];

작동하는 것 같습니다. blogTableViewCell은 셀의 IBOutlet이고 ChainesController는 파일의 소유자입니다.


1

관련 UITableView 문서에서 dequeueWithReuseIdentifier "재사용 할 셀 개체를 식별하는 문자열입니다. 기본적으로 재사용 가능한 셀의 식별자는 클래스 이름이지만 임의의 값으로 변경할 수 있습니다."

-reuseIdentifer를 재정의하는 것은 위험합니다. 셀 하위 클래스의 두 개의 하위 클래스가 있고이 두 가지를 단일 테이블보기에서 사용하면 어떻게됩니까? 재사용 식별자 호출을 super에 보내면 잘못된 유형의 셀을 대기열에서 빼게됩니다 .............. reuseIdentifier 메서드를 재정의해야한다고 생각하지만 대체 식별자를 반환해야합니다. 끈. 또는 지정되지 않은 경우 클래스를 문자열로 반환하도록합니다.


0

그 가치가 무엇인지, 저는 iPhone Tech Talks 중 하나에서 iPhone 엔지니어에게 이것에 대해 물었습니다. 그의 대답은 "예, IB를 사용하여 세포를 만드는 것은 가능합니다.하지만하지 마십시오. 제발,하지 마십시오."


1
이상하다. NY 토크에서 적어도 두 번의 토크에는 IB에서 생성 된 셀을 사용하는 데모 코드가있었습니다.
Shawn Craver

3
Apple의 Advanced Table View Cells 예제 프로젝트에서 IB를 사용하여 셀을 만들기 때문에 이것을 믿지 않습니다.
iwasrobbed

감사합니다. 할 때마다 문제가 발생합니다. 이것이 이유
skorulis

그는 아마도 그것에 대해 충분한 지식이 없었을 것입니다.
aryaxt

0

저는 Ben Mosher (감사합니다!)가 링크 한 Apple의 지시를 따랐지만 Apple이 중요한 점을 생략했음을 발견했습니다. IB에서 디자인하는 개체는 UITableViewCell 일 뿐이며 여기에서로드하는 변수도 마찬가지입니다. 그러나 실제로 UITableViewCell의 사용자 지정 하위 클래스로 설정하고 하위 클래스에 대한 코드 파일을 작성하는 경우 코드에 IBOutlet 선언 및 IBAction 메서드를 작성하고 IB의 사용자 지정 요소에 연결할 수 있습니다. 그런 다음 이러한 요소에 액세스하기 위해 뷰 태그를 사용할 필요가 없으며 원하는 모든 종류의 미친 셀을 만들 수 있습니다. 코코아 터치 천국입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.