【问题标题】:strange behaviour of objective C目标C的奇怪行为
【发布时间】:2012-10-30 15:39:35
【问题描述】:

实际上我来自java背景,我正在学习目标c。我对目标C的奇怪行为感到非常困惑。“请阅读第三个问题,它很重要。”

问题是按顺序提供的,所以请按我和其他人可以理解的顺序给出答案。

问题 1
我有两个派生自NSObject 的类:AB

@interface A : NSObject 
@end                               

@interface B : NSobject
-(void)display; // It displays "I am class B"
@end

现在如果我这样做:

A *a = [[B alloc]init]; // Show warning not error (it must be illegal)
[a display];            // prints "I am class B"

它调用了B类的显示方法。我认为它不应该发生,因为:

  1. A 没有方法display。通过多态性。

  2. 这可能是一个安全威胁,因为我正在创建任何类的引用并传递任何另一个类的对象并通过它访问数据。

  3. 可能存在设计问题,因为Dog 类实例获取了Printer 类的对象,现在我在Dog 实例上调用print 方法。

  4. 我引用了NSArray 并传递了NSMutableArray 的对象,现在我在这个实例上调用NSMutableArray 方法。

    [nsarr addObject:@:abc]; //看起来很奇怪

问题 2
如果我有Foo 协议并且如果任何课程没有确认它。不允许在协议引用中获取该类的对象。

@protocol Foo
@required
-(void)abc;
@end    

如果我打电话:

id<Foo> obj= [[B alloc]init]; // Shows warning ignore it for now as it must be illegal also
[obj display];                // It will call display method which should be illegal  
  1. 这不应该发生,因为B 不符合协议Fooobj 正在使用B 对象并调用B 实例方法。由于多态性和安全性,我认为它非常糟糕

问题 3
如果我的类有一个类方法返回该类的未自动释放的对象,编译器会显示警告。如果我将该类(不符合协议)方法返回的对象传递给协议的引用。 (这应该是一个错误)。

id<Foo> obj = [Abc aClassMethodReturnsObjectWhichNotAutoreleased]; //show warning

它显示了一个很好的警告。 Abc 不符合协议Foo

但是

id<Foo> obj = [NSArray arrayWithObjects:@"abc",@"def",nil]; // It does **not** show a warning as it will return autorelease object. NSArray doesn't conform protocol Foo

为什么上面对NSArray 类的赋值没有像上一个示例中显示的那样显示警告。

提前致谢。

编辑

*回答第三个问题:*由于 NSArray 返回 id 对象,这将允许传入“id obj”,但在“aClassMethodReturnsObjectWhichNotAutoreleased”情况下,该方法返回“ABC *”指针,这就是编译器的原因在这种情况下发出警告。

【问题讨论】:

  • 嗨,Sahil,欢迎来到 SO。如果您将此问题分成三个不同的问题,以便回答的人一次可以专注于一个主题,您很可能会得到质量更高的答案。
  • @Inafziger 感谢您的建议

标签: iphone objective-c ios ios5


【解决方案1】:

问题 1:

A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display];  //prints "I am class B"

在这里,您将静态类型 A 用于名为 a 的变量。然后将不同类型的对象 (B) 分配给变量。

与 java 不同,Objective-C 不强制静态类型要求,但它会在编译时警告你,因为编译器检测到声明的类型和对象的实际类型。不过,它很乐意将 B 对象填充到您的变量中,因此 a 现在指向您创建的 B 对象。一旦程序编译并运行(在运行时),A *a 的处理方式与id a 相同。

Objective-C 的另一个特点是您可以随时向任何对象发送任何消息。这是 Objective-C 动态特性的一部分。显然,在某些情况下,向对象发送错误消息会导致 坏事 (tm) 发生,因此您需要确保只发送适当的消息。有多种函数可以在运行时测试对象的类,甚至可以在发送之前测试它是否能够处理特定消息,以防止坏事。如果您使用的是静态类型(如本例所示),那么编译器将发出 警告 告诉您您可能犯了错误,应该检查代码。

问题 2:

这实际上与问题 1 非常相似。编译器警告您,您正在为变量分配看似不正确的值,但是在运行时您可以向任何对象发送任何消息,因此它将起作用在实际对象上,而不是类型声明中的“预期”对象。

问题 3:

好问题。我原以为你也会在那里收到警告。也许其他人可以在这方面提供帮助。我的第一个想法是这是一个错误,应该这样报告,但可能有一个我不知道的原因....

【讨论】:

  • @Inafziger 感谢您的解决方案。您能否提供一些参考资料,我可以获得更多详细信息
  • 实际上,@driis 提供了一个非常好的链接(启用静态行为)来讨论这个问题。如果您需要更多信息,请告诉我。
【解决方案2】:

正如您所发现的,Objective-C 和 Java 有非常不同的类型规则。

Java 是严格静态类型的,这意味着类型必须匹配,并且您永远不能进行类型转换规则不允许的赋值。

Objective-C 是动态类型的,带有可选的静态类型。您可以随时跳出类型系统。在某些情况下,编译器会发出警告,但仍然允许。

这就是您看到这种行为的原因。 Objective-C 并没有被破坏,它只是与你从 Java 中知道的规则不同。

Apple 有很多关于具体规则的文档,也许你会想阅读Enabling Static Behavior

这里有更多关于动态与静态类型的资源:

Dynamic type languages versus static type languagesWhat do people find so appealing about dynamic languages?

【讨论】:

  • 我不明白 - 评论是否意味着问题?在那种情况下是的,您从 Java 中知道的一些静态类型安全性在 Objective-C 中丢失了。但是动态类型实现了比静态语言所允许的更多的动态行为。这是一个折衷——Objective C 设计者选择动态类型。
【解决方案3】:
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display];  //prints "I am class B"

因为您从具有显示属性的 B 类初始化变量。 没错

【讨论】:

  • 对象 B 仅分配给携带对象 B 的变量 A。这就是 a 可以显示它的原因
  • @NeverBe 但是您在A类中没有显示方法,并且您将消息显示传递给没有实现它的A类。这是非法的,A和B没有任何关系。
  • a 不是类 A 的实例——查看它的值,您可以看到它是类 B 的实例。将其分配给 a 变量有点像调用猫狗。你可以随心所欲地称它为狗,但它仍然会喵喵叫。 (是的,将猫称为狗是令人困惑的。这就是编译器警告您不要这样做的原因。)
  • @SahilWasan objc 有更多的弹性语法:id obj = [B new]; [对象显示]。它会工作
  • @andyvn22 编译器只是在警告我,但在运行时它在“dog”实例上执行“meow”,据我说这一定是一个错误,因为你不能在“dog”上执行“meow” " 没有实现它的实例和 "dog" 与 cat 没有任何关系。
猜你喜欢
  • 1970-01-01
  • 2020-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 2019-04-10
相关资源
最近更新 更多