티스토리 뷰

발생일: 2016.04.01

키워드: UIView, tag, 태그 속성, 태그 프로퍼티

문제:
재사용되지 않는 UITableViewCell 에 특정 데이터를 담아뒀다가 꺼내쓰려고 한다.
기존 코드의 구조 상 UITableViewCell 을 상속할 수 없는 상태라서, 다른 방법이 있나 찾아봤더니 UIView 에 tag 라는 프로퍼티가 있다.

여기에 데이터를 담아뒀다가 꺼내쓰면 어떨까?


해결책:
UIView 의 tag 프로퍼티에는 특정 뷰를 구분하기 위한 NSInteger 형의 고유값을 할당할 수 있다.



저자는 tag 프로퍼티는 뷰를 구분하기 위한 목적으로만 사용해야지,
데이터를 저장하는 용도로 사용해서는 안된다고 가이드한다.


저자의 의도는 코드를 보면 쉽게 이해할 수 있는데,
아래 코드 블럭은 tag 프로퍼티에 데이터를 할당하는 잘못된 예제 중 하나이다.

- (void)configureThumbnailButton:(UIButton *)thumbnailButton
                        forPhoto:(NSUInteger)photoIndex {
    // ...
    thumbnailButton.tag = 1 + photoIndex;
    // ...
}

- (void)thumbnailButtonTapped:(id)sender {
    UIButton *thumbnailButton = sender;
    NSUInteger photoIndex = thumbnailButton.tag - 1;
    id selectedPhoto = [self.photoArray objectAtIndex:photoIndex];
    [self showPhoto:selectedPhoto];
}

tag 프로퍼티에 사진 인덱스를 할당하고, 클릭 시 tag 로부터 인덱스를 추출하는 로직이다.

이런 경우 tag 와 인덱스를 매칭하기 위해 매직넘버가 생길 수 밖에 없고,
tag 프로퍼티에 할당되어 있는 기본값 0과 데이터가 겹칠 수 있다는 문제가 발생한다.
(상수를 활용하거나, 기본값을 다르게 설정하는 방식으로 회피할 수 있겠지만 기본 맥락에 동의한다)


그 외, tag 프로퍼티에 할당된 좋지 않은 예제들이다.
코드를 보면 저자가 의도하는 바를 이해할 수 있다.

[pageScroller scrollRectToVisible:CGRectMake(1024 * (sender.tag - 101),
                                             0,
                                             1024,
                                             pageScroller.height)
                                             animated:YES];


NSString *name =
((UITextField *)[((UITableViewCell*)[self.view viewWithTag:i]).contentView viewWithTag:2]).text;


homeButton.tag = (int)@"home";



대신, 뷰에 데이터를 할당하고자 할 때엔, 서브클래스로 별도의 프로퍼티를 추가하거나 연관참조를 사용하는 것이 좋다고 가이드한다.

<서브클래스로 별도의 프로퍼티를 추가해 할당>

NSUInteger photoIndex = thumbnailButton.photoIndex;

또는

Photo *selectedPhoto = thumbnailButton.photo;


<연관참조를 사용>

static char kThumbnailButtonAssociatedPhotoKey;

- (void)setAssociatedPhoto:(Photo *)associatedPhoto
        forThumbnailButton:(UIButton *)thumbnailButton {
    objc_setAssociatedObject(thumbnailButton,
                             &kThumbnailButtonAssociatedPhotoKey,
                             associatedPhoto,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (Photo *)associatedPhotoForThumbnailButton:(UIButton *)thumbnailButton {
    objc_getAssociatedObject(thumbnailButton,
                                    &kThumbnailButtonAssociatedPhotoKey);
}


논의:
저자는 최대한 tag 프로퍼티에 데이터를 저장하지 않기를 추천하지만,
그래도 굳이 꼭 써야하다면 상수로 정의해 사용하기를 권장한다.

enum MyViewTags {
    kTitleLabelTag = 1,
    kSendButtonTag,
    kSomeOtherViewTag
};

// ...

if (sender.tag == kSendButtonTag) {
    // ...
}


개인적으론 셀의 개수가 많지 않다면, 상수로 설정해 tag를 활용하는 것도 적절한 선택이라 생각한다.
적절히 용도에 맞게 사용하자.


참고:
반응형
댓글
공지사항