programing

UITableViewCell에서 부모 UITableView 로의 참조?

nasanasas 2020. 11. 10. 08:15
반응형

UITableViewCell에서 부모 UITableView 로의 참조?


UITableView에서 소유에 액세스하는 방법 UITableViewCell있습니까?


테이블의 dataSource weak에서 설정 한 tableView에 대한 참조를 셀에 저장합니다 -tableView:cellForRowAtIndexPath:.

이것은 self.superview항상 tableView가 깨지기 쉬운 것에 의존하는 것보다 낫습니다 . Apple이 UITableView향후 뷰 계층 구조를 재구성하는 방법을 누가 압 니까?


특정 UITableView 계층에 의존하지 않는 더 좋은 방법이 있습니다. UITableView클래스 이름을 완전히 변경하지 않는 한 향후 iOS 버전에서 작동 합니다. 이럴 가능성은 극히 낮을뿐만 아니라, 이런 일이 발생하면 어쨌든 코드를 수정해야합니다.

아래 카테고리를 가져 와서 참조를 받으십시오. [myCell parentTableView]

@implementation UIView (FindUITableView)

-(UITableView *) parentTableView {
    // iterate up the view hierarchy to find the table containing this cell/view
    UIView *aView = self.superview;
    while(aView != nil) {
        if([aView isKindOfClass:[UITableView class]]) {
            return (UITableView *)aView;
        }
        aView = aView.superview;
    }
    return nil; // this view is not within a tableView
}

@end


// To use it, just import the category and invoke it like so:
UITableView *myTable = [myTableCell parentTableView];

// It can also be used from any subview within a cell, from example
// if you have a UILabel within your cell, you can also do:
UITableView *myTable = [myCellLabel parentTableView];

// NOTE:
// If you invoke this on a cell that is not part of a UITableView yet
// (i.e., on a cell that you just created with [[MyCell alloc] init]),
// then you will obviously get nil in return. You need to invoke this on cells/subviews
// that are already part of a UITableView.


업데이트
약한 참조를 유지하는 것이 더 나은 접근 방식인지에 대한 의견에 대한 토론이 있습니다. 상황에 따라 다릅니다. 뷰 계층 구조를 순회하면 대상 UIView가 식별 될 때까지 루핑하므로 약간의 런타임 패널티가 있습니다. 당신의 견해는 얼마나 깊습니까? 반면에 모든 셀에 대한 참조를 유지하면 메모리 패널티가 최소화되며 (약한 참조는 결국 포인터가 됨) 일반적으로 필요하지 않은 개체 관계를 추가하는 것은 여러 가지 이유로 잘못된 OO 설계 관행으로 간주되며 피하십시오 (아래 주석의 세부 사항 참조).

더 중요한 것은 셀 내부에 테이블 참조를 유지하면 코드가 복잡해지고 UITableViewCells재사용이 가능 하기 때문에 오류가 발생할 수 있습니다 . 재산을 UIKit포함하지 않는 것은 우연 이 아닙니다 cell.parentTable. 자신의 것을 정의하는 경우이를 관리하기위한 코드를 추가해야하며 효과적으로 수행하지 못하면 메모리 누수가 발생할 수 있습니다.

일반적으로 사용자가 셀과 상호 작용할 때 (단일 셀에 대해 실행) 위의 범주를 사용하고 테이블을 배치 할 때 [tableView:cellForRowAtIndexPath:](표시되는 모든 셀에 대해 실행 )이 아니므로 런타임 비용은 중요하지 않습니다.


Xcode 7 베타, Swift 2.0

이것은 나를 위해 잘 작동합니다. 제 생각에는 계층 구조와 관련이 없습니다. 지금까지이 접근 방식에 문제가 없었습니다. 많은 비동기 콜백에 이것을 사용했습니다 (예 : API 요청이 완료 될 때).

TableViewCell 클래스

class ItemCell: UITableViewCell {

    var updateCallback : ((updateList: Bool)-> Void)? //add this extra var

    @IBAction func btnDelete_Click(sender: AnyObject) {
        let localStorage = LocalStorage()
        if let description = lblItemDescription.text
        {
            //I delete it here, but could be done at other class as well.
            localStorage.DeleteItem(description) 
        }
        updateCallback?(updateList : true)

    }
}

DataSource 및 Delegate를 구현하는 내부 테이블보기 클래스

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: ItemCell = self.ItemTableView.dequeueReusableCellWithIdentifier("ItemCell") as! ItemCell!
    cell.updateCallback = UpdateCallback //add this extra line
    cell.lblItemDescription?.text = self.SomeList[indexPath.row].Description
    return cell
}

func UpdateCallback(updateTable : Bool) //add this extra method
{
    licensePlatesList = localStorage.LoadNotificationPlates()
    LicenseTableView.reloadData()
}

물론 어떤 변수를 넣을 수 updateCallback있고 tableView그에 따라 그 기능을 변경할 수 있습니다.

누군가는 확실히 사용하기 위해 저장되어 있는지 말해 줄 수 있습니다.


테이블 뷰 셀을 구성 할 때 UITableView에 대한 참조를 다시 추가해야합니다.

그러나 실제로 원하는 것은 UITableViewController에 대한 참조입니다. 동일한 것을 필요로합니다. 셀을 빌드하고 테이블보기에 전달할 때 셀의 대리자로 설정합니다.

An alternate approach if you are wiring up actions is to build the cells in IB, with the table view controller as the files owner - then wire up buttons in the cell to actions in the table view controller. When you load the cell xib with loadNibNamed, pass in the view controller as the owner and the button actions will be wired back to the table view controller.


If you have custom classes for your UITableViewCells, you can add an id type variable in your cell's header, and synthesize the variable. After you set the variable when you load the cell, you are free to do what you please with the tableview or any other higher view without much hassle or overhead.

cell.h

 // interface
 id root;

 // propery 
 @property (nonatomic, retain) id root;

cell.m

@synthesize root;

tableviewcontroller.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  // blah blah, traditional cell declaration
  // but before return cell;
  cell.root = tableView;
}

Now you can call any of the tableview's methods from within your cell using the root variable. (e.g., [root reloadData]);

Ah, takes me back to the good old days of flash programming.


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

The two methods in other answers are: (A) store a reference to the table, or (B) walk up the superviews.

I'd always use something like (A) for model objects and (B) for table cells.

Cells

If you are dealing with a UITableViewCell, then AFAIK you must either have the UITableView at hand (say you are in a table delegate method), or are dealing with a visible cell that is in the view hierarchy. Otherwise, you may well be doing something wrong (please note the "may well").

Cells are liberally reused and if you happen to have one that is not visible then the only real reason that cell exists is because of iOS UITableView performance optimization (a slower iOS version would have released and hopefully dealloc'd the cell when it moved off screen) or because you have a specific reference to it. I guess this is probably the reason that table cells are not endowed with a tableView instance method.

So (B) gives the right result for all iOS's so far, and all future ones until they radically change how views work.

Though in order to avoid writing generalizable code over and over, I'd use this:

+ (id)enclosingViewOfView:(UIView *)view withClass:(Class)returnKindOfClass {
  while (view&&![view isKindOfClass:returnKindOfClass]) view=view.superview;
  return(view);
}

and a convenience method:

+ (UITableView *)tableForCell:(UITableViewCell *)cell {
  return([self enclosingViewOfView:cell.superview withClass:UITableView.class]);
}

(or categories if you like)

BTW, if you are concerned about the effect of a loop with 20 or so iterations of that size on your app performance,.. don't.

Models

If you are talking about the model object that is displayed in the cell, then definitely that model could/should know about its parent model, which may be used to find, or trigger changes in, the table(s) that the cell's model might be displayed in. This is like (A), but less brittle with future iOS updates (eg one day they might make the UITableViewCell reuse cache exist per reuseidentifier, rather than per reuseidentifier per tableview, on that day all the implementations that use the weak reference method will break).

Th model method would be used for changes to the data displayed in the cell (i.e. model changes) since changes will propagate wherever the model is displayed (eg. some other UIViewController somewhere else in the app, logging, ...)

The cell method would be used for tableview actions, which would likely always be a bad idea if the cell isn't even a subview of a table (though it's your code, go nuts).

Either way, use a unit test rather than assuming that seemingly cleaner code just works when they update iOS.

참고URL : https://stackoverflow.com/questions/1110482/reference-from-uitableviewcell-to-parent-uitableview

반응형