UITableViewCell에서 UITableView를 얻는 방법?


100

나는이 UITableViewCell객체에 링크 된 나는 셀이 표시되는 경우 알 필요가있다. 내가 한 연구에서 이것은 내가 UITableView그것을 포함하는 것에 어떻게 든 접근해야 함을 의미 합니다 (거기에서 그것이 보이는지 확인하는 몇 가지 방법이 있습니다). 그래서에 UITableViewCell대한 포인터가 있는지 UITableView또는 셀에서 포인터를 얻는 다른 방법이 있는지 궁금합니다 .


2
이것의 목적은 무엇입니까?
max_ 2013 년

[cell superView]아마도?
Chris Loonam 2013 년

6
왜 이것이 필요하다고 생각하는지 설명 할 가치가 있습니다. 이것은 셀이 화면에 있는지 아닌지 알 수있는 많은 합법적 인 이유를 실제로 생각할 수 없기 때문에 잘못된 디자인의 신호일 수 있습니다.
Paul.s 2013 년

@ Paul.s 셀의 이미지에 제스처 인식기가 있으며 셀을 터치하면 다른 오버레이보기가 열립니다. 팝 오버 스타일을 생각하면 적절하게 표시하는 데 필요한만큼 셀을 오버레이해야합니다. 이 작업을 수행하려면 표시 할 TableView 또는 기타 뷰가 필요합니다. 솔루션에별로 만족 스럽지는 않지만 원하는 효과를 얻으려면 UITableViewCell의 UITableView를 얻는 것이 우리가 생각 해낸 최고입니다.
chadbag

1
@chadbag 걱정하지 마세요, 바라건대 같은 문제를 가진 다른 사람에게 아이디어를주었습니다.
PJ_Finnegan

답변:


153

iOS 버전을 확인하지 않으려면 UITableView가 발견 될 때까지 셀의 뷰에서 수퍼 뷰를 반복적으로 확인합니다.

id view = [tableViewCellInstance superview];

while (view && [view isKindOfClass:[UITableView class]] == NO) {
    view = [view superview]; 
}

UITableView *tableView = (UITableView *)view;

1
감사. 이것은 iOS 8에서 다시 한 번 변경된 것으로 보이며 모든 버전을 멋지게 처리합니다.
djskinner 2014 년

2
향후 업데이트에서 호환성 문제를 피하기 위해 tableview에 대한 약한 참조를 셀에 추가하는 것이 좋습니다.
Cenny

1
오히려 약한 방법. 나중에 뷰의 계층 구조가 변경되면 작동하지 않습니다.
RomanN 2015

2
실제로 tableview에 대한 포인터를 보유하는 약한 속성을 만드는 것이 더 좋습니다. 서브 클래스 @property (weak, nonatomic) UITableView *tableView;tableView:cellForRowAtIndexPath:그냥 cell.tableView = tableView;.
Alejandro Iván

현재 경험은 셀을 대기열에서 뺀 후 바로 테이블 뷰가 셀의 수퍼 뷰로 나타나지 않습니다. 다른 답변). 자동 레이아웃 및 기타 요인이 원인 일 수 있습니다.
Jonny

48

iOS7에서 베타 5 UITableViewWrapperViewUITableViewCell. 또한 UITableView의 수퍼입니다 UITableViewWrapperView.

따라서 iOS 7의 경우 솔루션은

UITableView *tableView = (UITableView *)cell.superview.superview;

따라서 iOS 6까지의 iOS의 경우 솔루션은

UITableView *tableView = (UITableView *)cell.superview;


5
오, 이것은 잔인한 API 변경입니다. 6과 7을 모두 지원하는 경우 Apple의 분기 모범 사례는 무엇입니까?
Ryan Romanchuk 2013 년

@RyanRomanchuk 다음은 한 가지 좋은 제안입니다. devforums.apple.com/message/865550#865550- 셀을 만들 때 관련 tableView에 대한 약한 포인터를 만듭니다. 또는 iOS 버전을 확인하고 적절한 superView를 반환 UITableViewCell하는 새 메소드 로 카테고리를 생성합니다 relatedTableView.
memmons

3
이를 위해 UIView에 재귀 범주를 작성하십시오. 버전을 확인할 필요가 없습니다. 테이블 뷰 셀이나 뷰 스택의 상단을 찾을 때까지 superview를 호출하십시오. 이것은 내가 아이폰 OS 6에 사용하고 아이폰 OS 7에서 수정없이 일을 그리고 아이폰 OS 8에 sitll 작동합니다 것입니다
스티븐 피셔

사면을 구걸; 나는 당신이 테이블보기를 찾을 때까지 의미했습니다. :)
Steven Fisher

39

Swift 5 확장

재귀 적으로

extension UIView {
    func parentView<T: UIView>(of type: T.Type) -> T? {
        guard let view = superview else {
            return nil
        } 
        return (view as? T) ?? view.parentView(of: T.self)
    }
}

extension UITableViewCell {
    var tableView: UITableView? {
        return parentView(of: UITableView.self)
    }
}

루프 사용

extension UITableViewCell {
    var tableView: UITableView? {
        var view = superview
        while let v = view, v.isKind(of: UITableView.self) == false {
            view = v.superview
        }
        return view as? UITableView
    }
}

엄지 손가락의 규칙은 힘이 풀기 사용하지 않는 것입니다
의 Thibaut 노아

1
@thibautnoah 포장을 풀기 view != nil전에 확인 이 있습니다 . 청소기 코드 불구로 업데이트
Orkhan Alikhanov

25

iOS7 이전에는 셀의 수퍼 뷰가 UITableView포함되었습니다. GM iOS7에 현재의 수퍼 셀이있다 (그래서 아마도 아니라 공개용 될 예정) UITableViewWrapperView의 수퍼은 인으로 UITableView. 문제에 대한 두 가지 해결책이 있습니다.

솔루션 # 1 : UITableViewCell카테고리 생성

@implementation UITableViewCell (RelatedTable)

- (UITableView *)relatedTable
{
    if ([self.superview isKindOfClass:[UITableView class]])
        return (UITableView *)self.superview;
    else if ([self.superview.superview isKindOfClass:[UITableView class]])
        return (UITableView *)self.superview.superview;
    else
    {
        NSAssert(NO, @"UITableView shall always be found.");
        return nil;
    }

}
@end

이것은을 (를) 사용하기위한 좋은 드롭 인 대체물 cell.superview이며 기존 코드를 쉽게 리팩터링 할 수 있습니다. 검색하고로 바꾸고 [cell relatedTable]어설 션을 던져 뷰 계층 구조가 나중에 변경되거나 되돌릴 경우 즉시 표시되도록합니다. 당신의 테스트에서.

솔루션 # 2 : 약한 UITableView참조 추가UITableViewCell

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

기존 프로젝트에서 사용하려면 더 많은 코드 리팩토링이 필요하지만 훨씬 더 나은 디자인입니다. 당신에 tableView:cellForRowAtIndexPath휴대 클래스로 사용 SOUITableViewCell 또는 있는지 확인하여 사용자 정의 셀 클래스에서 서브 클래스되는 SOUITableViewCell셀의있는 tableView 속성에있는 tableView를 할당합니다. 그런 다음 셀 내부에서를 사용하여 포함하는 tableview를 참조 할 수 있습니다 self.tableView.


솔루션 2가 더 나은 디자인이라는 데 동의하지 않습니다. 장애 지점이 더 많고 체계적인 수동 개입이 필요합니다. 첫 번째 솔루션은 실제로 매우 신뢰할 수 있지만 @idris가 약간의 미래 보장을 위해 그의 답변에서 제안한대로 구현할 것입니다.
devios1 2014

1
[self.superview.superview isKindOfClass:[UITableView class]]iOS 7이 점점 더 많아지기 때문에 테스트 가 첫 번째 여야합니다.
CopperCash

7

보이는 경우 수퍼 뷰가있는 것입니다. 그리고 ... 놀랍게도 ... superview는 UITableView 객체입니다.

그러나 수퍼 뷰가 있다고해서 화면에 있다는 보장은 없습니다. 그러나 UITableView는 표시되는 셀을 결정하는 방법을 제공합니다.

그리고 아니요, 셀에서 테이블로의 전용 참조가 없습니다. 그러나 UITableViewCell을 하위 클래스로 만들 때 하나를 도입하고 생성시 설정할 수 있습니다. (저는 하위 뷰 계층 구조를 생각하기 전에 많이했습니다.)

iOS7 업데이트 : Apple은 여기에서 하위보기 계층 구조를 변경했습니다. 상세하게 문서화되지 않은 작업을 할 때 평소처럼 상황이 변경 될 위험이 항상 있습니다. UITableView 개체가 결국 발견 될 때까지 뷰 계층 구조를 "크롤링"하는 것이 훨씬 절약됩니다.


14
이것은 더 이상 iOS7에서 사실이 아닙니다. iOS7 beta5에서 UITableViewWrapperView는 UITableViewCell의 수퍼 뷰입니다 ... 지금 당장 문제를 일으 킵니다
Gabe

댓글 주셔서 감사합니다. 그러면 내 코드 중 일부를 확인해야합니다.
Hermann Klecker 2013 년

7

Swift 2.2 솔루션.

특정 유형의 뷰를 재귀 적으로 검색하는 UIView의 확장입니다.

import UIKit

extension UIView {
    func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
        guard let view = self.superview as? T else {
            return self.superview?.lookForSuperviewOfType(type)
        }
        return view
    }
}

또는 더 콤팩트 (kabiroberai 덕분에) :

import UIKit

extension UIView {
    func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
        return superview as? T ?? superview?.superviewOfType(type)
    }
}

당신의 세포에서 당신은 그것을 부릅니다.

let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go

UITableViewCell은 cellForRowAtIndexPath 실행 후에 만 ​​UITableView에 추가됩니다.


당신은 전체 압축 할 수 있습니다 lookForSuperviewOfType:: 그것은 심지어 빠른-도망하고, 한 줄에 메서드 본문return superview as? T ?? superview?.superviewOfType(type)
kabiroberai

@kabiroberai, 감사합니다. 답변에 조언을 추가했습니다.
Mehdzor 2016-08-25

재귀 호출에서 사용하는 이름이 일치해야합니다. 따라서 읽어야합니다. ... ?? ? 수퍼 .lookForSuperviewOfType (유형)
로버트

7

수퍼 뷰를 호출하거나 응답자 체인을 통해 관리 할 수있는 모든 작업은 매우 취약 할 것입니다. 이를 수행하는 가장 좋은 방법은 셀이 무언가를 알고 자하는 경우, 셀이 묻고 자하는 질문에 답하는 방법에 응답하는 객체를 셀에 전달하고 컨트롤러가 응답 할 내용을 결정하는 논리를 구현하도록하는 것입니다. (귀하의 질문에서 나는 세포가 무언가가 보이는지 아닌지 알고 싶어한다고 생각합니다).

셀에 델리게이트 프로토콜을 생성하고, 셀의 델리게이트를 tableViewController로 설정하고 tableViewCotroller에서 모든 UI "제어"로직을 이동합니다.

테이블 뷰 셀은 정보 만 표시하는 덤 뷰 여야합니다.


대의원을 통해 더 좋을 수도 있습니다. 부모가 나에게 문제를 주었기 때문에 나는 일시적으로 테이블에 대한 참조를 사용하고 있습니다.
크리스티 Băluţă

1
내가 설명한 것은 기본적으로 델리게이트 패턴을 사용하는 것입니다. :)
Javier Soto 2014

이것은 받아 들여진 대답이어야하고, 사람들은이 질문을보고, 150 개 이상의 찬성 대답을보고 셀에서 tableView를 가져 오는 것이 좋으며 불행히도 그에 대한 강력한 참조를 유지할 수 있다고 생각합니다.
Alex Terente 2019

6

부모 tableView를 얻기 위해 UITableViewCell에 범주를 만들었습니다.

@implementation UITableViewCell (ParentTableView)


- (UITableView *)parentTableView {
    UITableView *tableView = nil;
    UIView *view = self;
    while(view != nil) {
        if([view isKindOfClass:[UITableView class]]) {
            tableView = (UITableView *)view;
            break;
        }
        view = [view superview];
    }
    return tableView;
}


@end

베스트,


3

위의 답변을 기반으로 한 Swift 버전 은 다음과 같습니다 . ExtendedCell나중에 사용하기 위해 일반화했습니다 .

import Foundation
import UIKit

class ExtendedCell: UITableViewCell {

    weak var _tableView: UITableView!

    func rowIndex() -> Int {
        if _tableView == nil {
            _tableView = tableView()
        }

        return _tableView.indexPathForSelectedRow!.row
    }

    func tableView() -> UITableView! {
        if _tableView != nil {
            return _tableView
        }

        var view = self.superview
        while view != nil && !(view?.isKindOfClass(UITableView))! {
            view = view?.superview
        }

        self._tableView = view as! UITableView
        return _tableView
    }
}

이 도움을 바랍니다 :)


2

이 솔루션 UITableViewWrapperViewUITableViewCell개체가 iOS7 beta5에서 개체 의 수퍼 뷰 라는 Gabe의 제안을 기반으로했습니다 .

하위 클래스 UITableviewCell:

- (UITableView *)superTableView
{
    return (UITableView *)[self findTableView:self];
}

- (UIView *)findTableView:(UIView *)view
{
    if (view.superview && [view.superview isKindOfClass:[UITableView class]]) {
        return view.superview;
    }
    return [self findTableView:view.superview];
}

2

위의 답변에서 약간을 빌려서 수정하고 다음 스 니펫을 얻었습니다.

- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
    id containingView = [containedView superview];
    while (containingView && ![containingView isKindOfClass:[clazz class]]) {
        containingView = [containingView superview];
    }
    return containingView;
}

클래스를 전달하면 다른 경우에 UITableView 이외의보기를 탐색하고 가져올 수있는 유연성이 제공됩니다.


2

이 문제에 대한 내 솔루션은 다른 솔루션과 다소 유사하지만 우아한 for 루프를 사용하며 짧습니다. 또한 미래에 대비해야합니다.

- (UITableView *)tableView
{
    UIView *view;
    for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
    return (UITableView *)view;
}

호출 될 때 셀이 아직 테이블보기에없는 경우 영원히 반복됩니다. 해결하려면, 전무에 대한 검사를 추가 : for (view = self.superview; view && ![view isKindOfClass:UITableView.class]; view = view.superview);
Antonio Nunes 보낸

2
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;

1

superview 대신 [ "UItableViewvariable"visibleCells]를 사용해보십시오.

나는 foreach 루프에서 그것을 사용하여 앱이보고 작동하는 셀을 반복했습니다.

for (UITableView *v in [orderItemTableView visibleCells])//visibleCell is the fix.
{
  @try{
    [orderItemTableView reloadData];
    if ([v isKindOfClass:[UIView class]]) {
        ReviewOrderTableViewCell *cell = (ReviewOrderTableViewCell *)v;
        if (([[cell deleteRecord] intValue] == 1) || ([[[cell editQuantityText] text] intValue] == 0))
            //code here 
    }
  }
}

매력처럼 작동합니다.


1

최소한 테스트되었지만이 비 일반적인 Swift 3 예제는 작동하는 것 같습니다.

extension UITableViewCell {
    func tableView() -> UITableView? {
        var currentView: UIView = self
        while let superView = currentView.superview {
            if superView is UITableView {
                return (superView as! UITableView)
            }
            currentView = superView
        }
        return nil
    }
}

0

이 코드 `UITableView *tblView=[cell superview];는 표보기 셀을 포함하는 UItableview의 인스턴스를 제공합니다.


UITableViewCell의 즉각적인 수퍼 뷰가 UITableView가 아니기 때문에 이것은 작동 하지 않습니다 . iOS 7부터 UITableViewCell 수퍼 뷰는 UITableViewWrapperView입니다. 덜 취약하고 안정적인 접근 방식에 대해서는 여기의 다른 답변을 참조하십시오.
JaredH

0

부모 UITableView를 찾으려면 이러한 방식으로 뷰 계층 구조를 탐색하는 것이 좋습니다.

- (UITableView *) findParentTableView:(UITableViewCell *) cell
{
    UIView *view = cell;
    while ( view && ![view isKindOfClass:[UITableView class]] )
    {
#ifdef DEBUG
        NSLog( @"%@", [[view  class ] description] );
#endif
        view = [view superview];
    }

    return ( (UITableView *) view );
}

그렇지 않으면 Apple이 뷰 계층 구조를 다시 변경할 때 코드가 손상됩니다 .

계층 구조를 가로 지르는 또 다른 대답 은 재귀 적입니다.


0
UITableViewCell Internal View Hierarchy Change in iOS 7

Using iOS 6.1 SDK

    <UITableViewCell>
       | <UITableViewCellContentView>
       |    | <UILabel>

Using iOS 7 SDK

    <UITableViewCell>
       | <UITableViewCellScrollView>
       |    | <UIButton>
       |    |    | <UIImageView>
       |    | <UITableViewCellContentView>
       |    |    | <UILabel>


The new private UITableViewCellScrollView class is a subclass of UIScrollView and is what allows this interaction:


![enter image description here][1]


  [1]: http://i.stack.imgur.com/C2uJa.gif

http://www.curiousfind.com/blog/646 감사합니다



0
extension UIView {
    func parentTableView() -> UITableView? {
        var viewOrNil: UIView? = self
        while let view = viewOrNil {
            if let tableView = view as? UITableView {
                return tableView
            }
            viewOrNil = view.superview
        }
        return nil
    }
}

0

@idris 답변에서 Swift에서 UITableViewCell에 대한 확장을 작성했습니다.

extension UITableViewCell {
func relatedTableView() -> UITableView? {
    var view = self.superview
    while view != nil && !(view is UITableView) {
        view = view?.superview
    }

    guard let tableView = view as? UITableView else { return nil }
    return tableView
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.