如何在运行时动态地将id类型转换为具体类?

时间:2009-05-22 17:43:04

标签: iphone objective-c cocoa dynamic key-value-observing

我有几个用于一个UIViewController的dataSource。我的视图控制器使用KeyValue Observing以便在运行时跟踪某些属性的状态。当我交换dataSources时,我需要停止观察这些属性。问题是,我不确定运行时dataSource的类,因此这样的东西是无效的:

if (aDataSource != dataSource) {
    // Ensure we stop observing the existing dataSource, otherwise bad stuff can happen.
    [dataSource removeObserver:self forKeyPath:@"someKeyPath"]; // not valid, compiler doesn't know what class dataSource is.
    [dataSource release];
    dataSource = [aDataSource retain];
}

编译器需要一个具体的类才能知道对象的接口。如何在这种特殊情况下获取dataSource类,然后为上面的removeObserver:forKeyPath:selector打印dataSource?我更喜欢动态/更聪明的东西,而不是在NSString实例中缓存类的名称,并在每次切换时引用它。意思是,我总是可以这样做:

NSString *lastDataSource = @"MyClass";
Class foo = [NSClassFromString(lastDataSource)];

感谢。

4 个答案:

答案 0 :(得分:6)

  1. 如果你这样编码:

    id foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    编译器可以正常使用它,因为类型为id的对象接受任何消息(只要编译器知道签名)。

  2. 现在,如果你有:

    id<NSObject> foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    编译器会给你一个警告:

      

    警告:'-removeObserver:forKeyPath:'未找到协议

    这是因为你所指的协议NSObject不是指定义KVO方法的NSObject类。

  3. 但如果你有:

    NSObject* foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    那也可以正常编译,因为在这种情况下你使用的是NSObject类。

  4. 相关链接:

答案 1 :(得分:2)

你的意思是什么无效?你有编译错误吗?

Objective-C默认支持对象的动态类型。您应该能够在Objective-C中的任何对象上调用任何方法,即使编译器无法保证该对象支持该方法的静态类型。

答案 2 :(得分:1)

我认为您需要将它们转换为NSObject *,因为这是KVO方法所在的位置(不在NSObject协议中)。

答案 3 :(得分:1)

让我补充一下你概述的方法......

NSString *lastDataSource = @"MyClass";
Class foo = [NSClassFromString(lastDataSource)];

...当然不能压制编译时警告,因为类“foo”只能在运行时计算。因此,即使你作为程序员可以从代码中清楚地看到“foo”最终会成为“MyClass”类,编译器也不清楚这一点,所以如果“MyClass”有一个方法“myMethod:”你会如果将该消息发送到声明为“foo”的对象,仍然会收到编译器警告。

我猜你已经意识到了这一点,但最好还是要明确为什么这种方法无法解决你的问题。