티스토리 뷰
발생일: 2016.04.01
키워드: UIView, tag, 태그 속성, 태그 프로퍼티
문제:
재사용되지 않는 UITableViewCell 에 특정 데이터를 담아뒀다가 꺼내쓰려고 한다.
기존 코드의 구조 상 UITableViewCell 을 상속할 수 없는 상태라서, 다른 방법이 있나 찾아봤더니 UIView 에 tag 라는 프로퍼티가 있다.
여기에 데이터를 담아뒀다가 꺼내쓰면 어떨까?
해결책:
UIView 의 tag 프로퍼티에는 특정 뷰를 구분하기 위한 NSInteger 형의 고유값을 할당할 수 있다.
검색해보니, Mike Weller 라는 개발자의 글 중 tag 프로퍼티 활용에 대한 좋은 글이 있고, 나도 동의한다.
저자는 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를 활용하는 것도 적절한 선택이라 생각한다.
적절히 용도에 맞게 사용하자.
참고:
반응형
댓글
공지사항