【问题标题】:Objective-C: Dynamic binding changes a variable's declared class type?Objective-C:动态绑定改变变量声明的类类型?
【发布时间】:2014-03-21 08:10:03
【问题描述】:

我是objective-c 的新手。刚才在学习使用id,写了如下代码:

NSString *str = @"x";
id obj = str;
NSArray *arr = obj;
NSLog(@"%@, %@\n", str.className, arr.className);

在 Xcode 中执行,输出为__NSCFConstantString, __NSCFConstantString,没有任何警告。考虑到arr 最初被声明为NSArray,有人可以告诉我为什么会这样吗?

我也试过直接将arr赋值给str,如下:

NSString *str = @"x";
NSArray *arr = str;
NSLog(@"%@, %@\n", str.className, arr.className);

虽然在xcode中出现了警告,但是可以成功执行,输出还是一样的__NSCFConstantString, __NSCFConstantString。为什么?

我花了很长时间在互联网上搜索,但没有找到一个好的答案。请帮忙!谢谢!

【问题讨论】:

  • 你能显示 s 变量的声明吗?
  • @Greg:这可能是复制/粘贴错误,应该是str
  • @Greg:抱歉打错了。我刚刚纠正了它

标签: objective-c casting dynamic-binding


【解决方案1】:

在这两种情况下,strarr 都是指向同一个对象的指针。

Objective-C 方法在运行时解析,str.className[str className],表示

str指向的对象发送className消息。

因此str.classNamearr.className 在 同一个实例。

指针的声明类型(NSString *NSArray *)未用于方法 解析度。你甚至可以打电话

[obj className];

与您的id obj

在第二种情况下,编译器可以警告您分配不同类型的 指针。在第一种情况下这是不可能的,因为 id 是一个通用指针 可以与任何 Objective-C 指针相互转换(有点类似于 C 语言中的void *)。

【讨论】:

  • 感谢您的回复!所以基本上,strarr 不需要像它们被初始化的那样是类类型?为什么使用这种机制?好用吗?
  • @Giantron:看看developer.apple.com/library/ios/documentation/general/…,也许会有帮助。 - 另请注意,声明 NSString *str 不会初始化 任何内容。 strarr 只是指针。它们声明的类型仅由编译器使用,而不是在运行时使用。
  • 谢谢,马丁。我只是习惯了指针应该指向它所声明的内容。 objective-c 似乎通过动态绑定提供了更大的灵活性。而且,由于它是在运行时解析的,所以每个指针都可以声明为 id.. 但这可能不是一个好习惯?
  • @Giantron:类型应该尽可能具体。如果您知道(或期望)该对象是SomeClass 的实例或子类的实例,则使用SomeClass *。如果您知道它是一些符合协议的对象,请使用id<protocol>。如果您什么都不知道,请使用id。这允许编译器进行尽可能多的错误检查。
【解决方案2】:

你只创建了一个对象,属于一个类。看,你的代码有两部分:

  1. 对象的实际实例

    在您的情况下,您真正​​创建对象的唯一时间是您编写 @"x"。

  2. 指向这些对象的指针(包含内存地址的变量)

当你说

NSString* str

NSArray* arr

id obj

你所做的只是创建一个指针变量。在底层,指针变量只是一个可以保存数字的变量。像一个int。只是它旨在包含对象的内存地址。您可以将指针变量想象成一张餐巾纸,有人在上面写下平房街道地址的楼号。

然后你会拿第二张(和第三张)餐巾纸并在上面写下相同的楼号。然而,餐巾纸上并没有注明这是一栋平房,而是餐巾纸上的“arr”实际上说这是一栋公寓楼(NSArray)。而在“obj”餐巾纸上,你甚至都懒得写它是什么(id)。

仅仅因为你的餐巾纸上写着这个地址是指公寓,并不会改变你街道上那个号码的房子。

你给指针变量的类型只是给编译器的一个提示,所以当你不小心把你的对象弄混时它会警告你。当您将它们的地址写入不同类型的指针变量时,不会执行从一种对象类型到另一种类型的转换。通常,如果将一种类型的对象的地址分配给另一种类型的指针变量,则会收到错误消息。但是由于您要通过 'id' 类型的 'obj' 变量,因此您绕过了此检查。 'id' 用于您只关心处理对象的情况。

例如NSArray 保存任何类型的对象列表,但并不真正关心哪种类型。所以它使用“id”作为它保留的地址类型。这样,您只需要一个数组类,而不是一个 NSStringArray 和另一个 NSNumberArray 等。为了使这种情况更方便,每当涉及“id”变量时,编译器不会发出警告并假设您知道自己在做什么做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-22
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 2010-12-22
    • 2013-11-15
    • 1970-01-01
    相关资源
    最近更新 更多