在 UITabbarController 中设置视图控制器的委托

Posted

技术标签:

【中文标题】在 UITabbarController 中设置视图控制器的委托【英文标题】:Set delegate of viewcontrollers in UITabbarController 【发布时间】:2013-06-03 15:04:45 【问题描述】:

我的应用中有以下设置:

带有 3 个视图控制器的 UITabbarController,内嵌 UINavigationController。 3 个视图控制器从称为“SVC”的 UIViewController 子类继承/超类,以实现在所有 3.视图控制器中使用的元素并防止重复代码。在这个“SVC”类中,我设置了一个名为“dismissDelegate”的委托(用于判断 tabbarcontroller 何时被关闭)。

@protocol ModalViewDelegate <NSObject>

    - (void)didDismissModalViewFrom:(UIViewController *)viewController;

@end
   @property (weak, nonatomic) id <ModalViewDelegate> dismissDelegate;

我的另一个视图控制器与 UITabbarController 连接,实现了这个委托,以便获取有关何时关闭 tabbarcontroller 的信息。

SVC 类通知代理解除标签栏,如下所示:

 [self.dismissDelegate didDismissModalViewFrom:self]; 

我现在想将所有从 SVC 类(所有标签栏视图控制器)继承的视图控制器的委托设置为这个视图控制器,我尝试通过 prepareToSegue 方法来执行此操作,如下所示:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender


   if ([[segue identifier] isEqualToString:@"ToTab"]) 


        UITabBarController *tabBarController = segue.destinationViewController;

        for (UINavigationController *navController in  tabBarController.viewControllers) 


            for (UIViewController *vc in navController.viewControllers) 
                _SubclassVC = (SVC *) vc.superclass;
                _SubclassVC.dismissDelegate = self; 

            

        


    


但我收到以下错误:

+[SVC setDismissDelegate:]: unrecognized selector sent to class 0xbca68

我的问题:

    这是解决此问题的正确方法(获取有关解除视图控制器的信息并在由多个视图控制器继承的子类中设置此委托)? 如何将我的第一个视图控制器设置为选项卡栏中所有视图控制器的代表 - SVC 类,以便在关闭选项卡控制器时收到通知并解决错误?

【问题讨论】:

【参考方案1】:
+[SVC setDismissDelegate:]: unrecognized selector sent to class 0xbca68

查看+

加号表示您正在调用类方法。您一定尝试过通过 setter 设置类变量。但是属性仅代表实例变量。因此,自动生成的 setter 和 getter 只是实例方法。 (在这样的错误消息中以减号 - 开头)。

这就是你所做的:

        _SubclassVC = (SVC *) vc.superclass;
        _SubclassVC.dismissDelegate = self;

无论出于何种原因(可能是错误或误解),您获取 vc 实例并获取其superclassvc.superclass 返回一个类对象,而不是一个对象(意思是不是一个实例,在 Obj-C 中类对象也是对象)。 然后您将其类型转换为 (SVC *) 只是为了阻止编译器抛出错误(或警告 - 不确定)。

好吧,我猜你想知道为什么你必须对它进行类型转换。这就是原因:)

接下来,您将self 分配给属性dismissDelegate。编译器这样做是因为您将它类型转换为具有属性dismissDelegate 的 SVC*。在这样的结构中,编译器实际上会像往常一样调用 setter setDismissDelegate

但在运行时消息(或选择器)setDismissDelegate: 不会发送到SVC*,而是发送到class 对象。并且SVC 类没有方法(或选择器)+setDismissDelegate:,因此无法解析消息。这正是错误消息告诉您的内容。

好的,现在我们来回答您的问题。 1. 嗯,这不是我会做的方式,但这肯定是实现它的一种方式。 2.如果你想坚持这种不寻常的方法,那么做这个小改动,你就会摆脱错误:

for (SVC *vc in navController.viewControllers) 
    vc.dismissDelegate = self; 

获取超类对象没有意义。如果您无法访问超类的属性,那么您在继承链上做错了。 如果你想在保存方面:

for (UIViewController *vc in navController.viewControllers) 
  if (vc isKindOfClass:[SVC class])  //BTW, this is good usage of the class object
    SVC *svc = (SVC*) vc;
    svc.dismissDelegate = self; 
  

【讨论】:

哇,非常感谢您的快速回答和帮助:)。由于我在 Obj-c 编程方面相当陌生并且想学习我会很想听听您的方式吗?非常感谢:)。 这取决于目的。大多数类似的任务都可以通过覆盖 viewWillAppear 和 viewWillDisappear 来完成。但我不知道你为什么要这样做。像您一样使用委托模式并不是最糟糕的主意。如果你想正确地做到这一点,那么在协议中声明它的方法,并在调用它们之前检查协议是否符合。 (基本相同,但更优雅。)虽然这可能是 NSNotificationCenter 和 NSNotification 对象的一个​​很好的用途。同样,不知道目的很难说。 感谢您的评论 :)。我有一个名为“SVC”的 UIViewController 子类的原因是为了实现在所有 3.viewcontrollers 中使用的元素并防止重复代码,但我会尝试使用 viewWillAppear、viewWillDisappear 来代替 :)。因此,当我声明一个协议(类)时,我会在设置委托之前执行 if ([_svc respondsToSelector:@selector(setDismissDelegate:)]) 之类的操作,这就是您的意思吗?它的唯一用途是确定何时关闭(模态)视图控制器:)。感谢您的帮助和善意。 好吧,当我们询问 WHY 时,我们并不是说您是子类化这一事实。子类化几乎总是有充分的理由。问题是,当下面的某些视图控制器被解除时,为什么需要通知您。这听起来更像是架构问题,而不是编程故障。 是的。在调用方法之前,您始终可以使用respondsToSelector。没事儿。这并没有错。相反。但是当您使用协议时,您可以以类似的方式使用conformsToProtocol:@protocol(name)。这更像是对委托模式的正确使用。

以上是关于在 UITabbarController 中设置视图控制器的委托的主要内容,如果未能解决你的问题,请参考以下文章

UITabBarController 问题中的 UINavigationController

在 UITabBarController 中推送 ViewController

从 xib 创建 UITabBarController 时出现黑屏

从一个 UITabBarController 导航到另一个 UITabBarController

如何在 UITabBarController 中向 UINavigationController 添加右键?

在 UITabBarController 中,moreNavigationController 始终为零