UITableViewCell中button跳转下一界面的几种方式

开发中最为常见的功能,UITableViewCell中有个button需要跳转到下一个界面。
那么如何实现该功能,大致有三种办法:

PlanA:利用UIResponder响应链,寻找父层视图,直到找到UIViewController

概述:App使用响应者对象接收和处理事件,响应者对象是任何UIResponder的实例。UIResponder的子类包括UIView,UIViewController,UIApplication等。响应者接收到原始事件数据,必须处理事件或者转发到另一个响应者对象。当你的App接收到一个事件时,UIKit自动引导事件到最合适的响应者对象,也叫做第一响应者。

简单的说,我们一个界面会堆叠很多层的view,而点击事件一般会认为最上层的view是第一响应者。其他是二三四五六响应者。
我们可以通过nextResponder方法来获取这些响应者队列中的对象。

这种方法最好,低耦合,无循环引用的风险。(唯独对于不熟悉的人,阅读代码需要转个弯)

写法1:直接找下一个响应者对象

//只要是你的view在ViewController中,这条语句都会成功
//view在ViewController外,会陷入死循环,切记
-(UIViewController*)parentController{
    UIResponder *responder = [self nextResponder];
    while (responder) {
        if ([responder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)responder;
        }
        responder = [responder nextResponder];
    }
    //返回nil时候默认不会执行跳转
    return nil;
}

写法2:先找当前view的superview,再找这个superview的下一个响应对象

//这种写法要求你的view在vc.view中
//因为这个写法会直接找self的superview,而[vc.view superview] = nil
- (UIViewController *)parentController{
    for (UIView *next = [self superview]; next; next = next.superview) {
        UIResponder *nextResponder = [next nextResponder];
        if ([nextResponder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)nextResponder;
        }
    }
    //返回nil时候默认不会执行跳转
    return nil;
}

注:其实代码片段里的循环次数不会很多,不用担忧消耗内存。

PlanB:把view或者nav作为属性传进cell中

cell无法跳转下一界面的问题,主要是拿不到vc或者nav,所以我们把对象传进cell中,并控制好循环引用就好。
这种方法最符合普通逻辑,但在某些复杂情况下,可能造成内存泄漏。

cell的.h文件中声明

@interface TestTableViewCell : UITableViewCell
//注意,这里一定是weak修饰符
@property(nonatomic,weak)UINavigationController *nav;
//注意,这里一定是weak修饰符
@property(nonatomic,weak)UIViewController *rootView;
@end

然后在vc中的tableView:cellForRowAtIndexPath:方法中如此写

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier" forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"%d",self.count];
    //只需要在cell中把nav属性声明为weak即可,这里不需要若引用
    cell.nav = self.navigationController;
    //只需要在cell中把rootView属性声明为weak即可,这里不需要若引用
    cell.rootView = self;
    //总结,外部是否使用弱应用对于cell无影响,cell中的属性设置weak才有效
    
    return cell;
}

然后即可正常跳转

-(IBAction)goNextView:(id)sender{
    TestTableViewController *testTableView = [[UIStoryboard storyboardWithName:@"TestStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"TestTableView"];
    //带nav执行跳转
    [self.nav pushViewController:testTableView animated:YES];
    //不带nav执行跳转
    [self.rootView presentViewController:testTableView animated:YES completion:nil];
}

PlanC:利用bolck方式把点击事件传回ViewController

最早,可能大家用的都是这个方法,但实际上他的缺点有三:
1.block有造成内存泄漏的风险,需要使用__weak修饰符
2.如果这个cell中包含多个按钮,就意味着每个按钮都需要一个点击block。增加代码量
3.如果这个cell被多个tableView使用,每个tableView都需要把block代码块带上,这就产生了重复代码。

TestTableViewCell.h

@interface TestTableViewCell : UITableViewCell
//block一般用copy修饰符
@property(nonatomic,copy)void (^buttonClickBlock)(void);

@end

TestTableViewCell.m

-(IBAction)goNextView:(id)sender{
    if (self.buttonClickBlock) {
        self.buttonClickBlock();
    }
}

然后在vc中的tableView:cellForRowAtIndexPath:方法中如此写

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier" forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"%d",self.count];
    //切记,这里一定创建弱引用的weakSelf,再在cell的block中使用,否则必定会内存泄漏
    __weak UIViewController *weakSelf = self;
    [cell setButtonClickBlock:^{
        TestTableViewController *testTableView = [[UIStoryboard storyboardWithName:@"TestStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:@"TestTableView"];
        [weakSelf.navigationController pushViewController:testTableView animated:YES];
    }];
    
    return cell;
}

附录:几种错误的写法

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier" forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"%d",self.count];
    //经测试,如果cell中不对于nav属性声明weak,那么及时在此弱应用也是无效的
    __weak UINavigationController *weakNav = self.navigationController;
    cell.nav = weakNav;
    //经测试,如果cell中不对于rootView属性声明weak,那么及时在此弱应用也是无效的
    __weak UIViewController *weakSelf = self;
    cell.rootView = weakSelf;
    //总结,外部是否使用弱应用对于cell无影响,cell中的属性设置weak才有效
    
    return cell;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 5,996评论 4 26
  • 重点参考链接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi阅读 4,411评论 0 15
  • 芳草无意与争春,柳絮绵绵怎奈何姹紫嫣红落英缤纷。 春雨绵绵了无迹,大雨滂沱怎堪比沁人心脾润物无声。 有心栽花,花不...
    小牛老师阅读 378评论 0 1
  • 今日自我觉察: 昨天,两位朋友来工作室交流学习。一位朋友的大嗓门让我忍不住多次提醒他:小点声。 其实,之前自己也是...
    自由自在的白云阅读 238评论 0 1