3

实际上我来自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,现在我正在实例上调用print方法。Dog

  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不符合协议Foo并且obj正在获取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 *”指针,这就是编译器在这种情况下发出警告的原因。

4

3 回答 3

2

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

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

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

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

Apple 有很多关于特定规则的文档,也许您想阅读启用静态行为

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

动态类型语言与静态类型语言以及人们发现动态语言有什么吸引人的地方?

于 2012-11-10T14:48:31.560 回答
2

问题一:

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:

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

于 2012-11-10T15:58:14.800 回答
1
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display];  //prints "I am class B"

因为您从具有显示属性的 B 类初始化变量。这是正确的

于 2012-11-10T14:48:11.390 回答