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

发布于 2024-07-21 05:31:10 字数 780 浏览 5 评论 0原文

我有多个数据源用于一个 UIViewController。 我的视图控制器使用 KeyValue 观察来跟踪运行时某些属性的状态。 当我交换数据源时,我需要停止观察这些属性。 问题是,我不确定运行时数据源的类,因此这样的事情是无效的:

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: 选择器类型化 dataSource? 我更喜欢动态/智能的东西,而不是在 NSString 实例中缓存类的名称并在每次切换时引用该名称。 意思是,我总是可以做这样的事情:

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

谢谢。

I have several dataSources I use for one UIViewController. My view controller uses KeyValue Observing in order to follow the state of certain properties at runtime. When I swap dataSources, I need to stop observing those properties. The problem is, I'm not sure of the class of the dataSource at runtime, therefor something like this is not valid:

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];
}

The compiler needs a concrete class in order to know the object's interface. How can I grab the class of dataSource in this particular case, and then typcast the dataSource for the removeObserver:forKeyPath: selector above? I prefer something dynamic/smarter than caching the name of the class in an NSString instance and referring to that whenever I switch. Meaning, I could always do something like:

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

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

帝王念 2024-07-28 05:31:10
  1. 如果你的代码是这样的:

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

    编译器会很好地处理它,因为类型为 id 的对象接受任何消息(只要编译器知道签名)。

  2. 现在如果你有:

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

    编译器会给你一个警告:

    <块引用>

    警告:协议中未找到“-removeObserver:forKeyPath:”

    这是因为您引用的是协议 NSObject,而不是定义 KVO 方法的 NSObject 类。

  3. 但是如果你有:

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

    这也可以很好地编译,因为在本例中您使用的是 NSObject 类。

相关链接:

  1. If you code like this:

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

    The compiler will be fine with it as objects with type id accepts any message (as long the signature is known to the compiler).

  2. Now if you have:

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

    The compiler will give you a warning:

    warning: '-removeObserver:forKeyPath:' not found in protocol

    This is because you're referring to the protocol NSObject not to the NSObject class where the KVO methods are defined.

  3. But if you have:

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

    That will compile fine too, as in this case you're using the class NSObject.

Related links:

十二 2024-07-28 05:31:10

您说它无效是什么意思? 您收到编译错误吗?

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

What do you mean it is not valid? Do you get a compile error?

Objective-C supports dynamic typing for objects by default. You should be able to call any method on any object in Objective-C, even if the compiler can't guarantee from the static type that that object supports that method.

清醇 2024-07-28 05:31:10

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

I think you need to cast them to NSObject *, since that's where the KVO methods are (not in NSObject protocol).

老子叫无熙 2024-07-28 05:31:10

让我补充一点,您概述的方法......

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

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

我猜您已经意识到这一点,但最好明确说明为什么该方法无法解决您的问题。

Just let me add that the approach you outline with ...

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

... will of course not be able to supress your compile-time warnings, since the class "foo" will only get calculated at run-time. So even though you as the programmer can plainly see from the code that "foo" will end up being the class "MyClass", this is not clear to the compiler, and so if "MyClass" has a method "myMethod:" you will still get a compiler warning if you send that message to an object declared as "foo".

I'm guessing you realise this, but it's better to make it clear why that approach won't solve your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文