Objective-C:你可以为静态类类型测试一个未初始化的指针吗?

时间:2011-10-06 20:50:28

标签: objective-c ios cocoa pointers null

我正在尝试做一些事情:

某些对象中的

UITableVIewController *viewController;
[someObjectB setupView: viewController];

在某个对象B中:

-(void) setupView:(UIViewController*)view
{
    if the pointer passed in is of type UITableViewController then ...
    say, for instance with: [[view class] isKindOfClass [UITableViewController class]]
    or: [view isKindOfClass [UITableViewController class]]
}

但是,我有两个问题: 首先,参数作为UIViewController进入B中的方法,UIViewController是UITableView的超类(我正在这样做,因为这个方法也会配置其他类型的视图控制器)。所以我想知道,如果我将UITableViewController传递给UIViewController类型的方法参数,isKindOfClass仍然可以进行动态绑定吗?也就是说,运行时检查内容的类型,而不管指针的静态类型是什么?

其次,请注意我在将对象A传递给B之前没有初始化它。我实际上希望B初始化它。但随后购买问题变成了,如何在未初始化的指针上测试静态指针类型?也就是说,在B里面:[view isKindOfClass [UITableViewController class]]给了我一个BAD_EXEC。我猜,因为我显然试图访问jul指针。那么还有一种方法可以根据指针静态类型声明进行测试吗?

ADDENDUM :(因为我将其添加为评论,抱歉)

让我用更具体的术语重新解释这个问题的一部分:我希望obj B创建一个UITableViewController类型的变量,将它传递给A并让A知道它已经被赋予了一个指向UITableViewController的指针,因此它实际上可以初始化这个指向UITableViewController的特定子类的指针,然后obj B将现在初始化的对象传递给其他对象。

我想要这样做的理由是以下场景: 我有一个基于navigationController的应用程序。它有一个带按钮的根控制器,根据按下的按钮,根控制器实例化并推送数据库的不同表的表控制器,反过来,当单击这些表的一行时,表实例化并推送详细视图控制器。

到目前为止一直很好,但由于项目的性质,我想保持整个navigationcontroller实例化 - 推送链不可知的事实是有一个数据库,并且表和详细视图控制器实际上是特定的子类分别是UITableViewController和UIViewController。

这意味着流程将是:

1-单击,根控制器将通用UIViewController传递给我的自定义主控制器。

2-这个主控制器意识到已经传递了一个通用表,将它初始化为我定义的特定子类,并做了一些事情来为它提供来自sql数据库的数据。

3 - 根控制器,不关心通用UIViewController是否是一个表,甚至不关心UIViewController的子类,只是将它推送到navigationController。

同样,我的想法是,我不需要在根控制器中包含表子类的标头。只有自定义主控制器知道这些。

所以,在一天结束时,我看到这样做的方式是能够确定传递的指针的类型是什么,无论这个指针是否为nil,指向垃圾或指向一个实际对象。含义:

UIVIewController * a - >静态类型声明,在编译时确定。

a = [UIVIewController alloc的一些子类] init]; - >指针内容的动态类型,在运行时确定,可能是通过激活记录跟踪链接。类似于C ++中的“虚拟”

3 个答案:

答案 0 :(得分:2)

Objective-C是一种按值传递的语言,就像C一样。您不能使用您在那里的代码初始化对象A中的viewController。初始化它,将其地址传递给setupView:,然后根据需要进行初始化:

UITableVIewController *viewController = nil;
[someObjectB setupView:&viewController];

-(void)setupView:(UIViewController**)view
{
   if (*view == nil)
      // initialize it  - *view = [[blah alloc] init] or whatever
   else
       ...

}

答案 1 :(得分:2)

在回答第一个问题时,是 - Objective C将在运行时(动态)确定对象的类类型。在回答第二个问题时,任何调度到nil对象的方法调用都会被忽略,因此所有类检查都不会真正起作用。但是你不应该得到BAD_EXEC,除非你:

  • 先前初始化对象并释放它而不设置为nil,导致其内存地址为垃圾
  • 传入由未创建的未初始化的自动变量 编译器给你
  • 无论出于何种原因,将其指向内存中的一些荒谬地址。

*编辑*

添加了一个可以获得BAD_EXEC的场景,另外,请参阅下面的链接,了解测试类相等性时的几个问题,特别是使用isKindOfClass方法。

In Objective-C, what is the equivalent of Java's "instanceof" keyword?

答案 2 :(得分:2)

正如其他人所指出的那样,你所要求的是不可能的。将变量传递给方法时,它只发送值,而不是类型。此外,运行时不了解方法中变量的类型。任何变量类型处理都由编译器完成。运行时只能知道变量所持有的对象的类。

作为替代方案,如果您可以更改方法的签名,则可以添加一个参数来指示要创建的对象的类型。调用方法仍然不需要知道对象的确切类型,只需知道它是否是表视图控制器。这是一个使用枚举来保存不同类型的示例。

// header

enum ViewControllerType {
    ViewControllerNormal = 0,
    ViewControllerTableView
};
- (void)setupView:(UIViewController **)view ofType:(enum ViewControllerType)type;

// implementation

- (void)setupView:(UIViewController **)view ofType:(enum ViewControllerType)type {
    if(!view) {
        NSLog(@"setupView:ofType: received nil pointer");
        return;
    }
    switch(type) {
        case ViewControllerNormal:
            // create normal UIViewController type
            break;
        case ViewControllerTableView:
            // create UITableViewController type
            break;
        default:
            NSLog(@"setupView:ofType: received unknown type: %i",type);
            return;
    }
}

用过:

UIViewController *view;
[creatorObject setupView:&view ofType:ViewControllerNormal];
// or
UITableViewController *tableView;
[creatorObject setupView:&tableView ofType:ViewControllerTableView];