为什么类型为contentView
的{{1}}类的NSWindow
属性而不是id
这对我来说没有意义,为什么contentView应该是NSView
子类以外的任何东西。
所以在我的情况下,我必须像这样输入它才能访问它的框架:
NSView
而不是编译器不喜欢的那样:
NSView *contentView = self.window.contentView; // returns an `id`
CGRect frame = contentView.frame
答案 0 :(得分:9)
这可能是历史性的。 Objective-C支持严格的输入,但它也支持“duck typing”,你不关心对象是什么 class ,你关心它响应的消息(也就是说,如果它看起来像一只鸭子,它像鸭子一样嘎嘎叫,它可能是一只鸭子)。您可以将每个对象指针键入id
并发送任何消息。实际上,接收者无需为其收到的任何消息实现方法:它也可以将消息转发给另一个对象。
在Application Kit中 - OpenStep和Cocoa的前身GUI框架 - 几乎所有对象都是通过duck typing来使用的。这是应用程序工具包3.2版本中Window
的(部分)接口。
@interface Window : Responder
{
NXRect frame;
id contentView;
id delegate;
id firstResponder;
id lastLeftHit;
id lastRightHit;
id counterpart;
id fieldEditor;
int winEventMask;
int windowNum;
float backgroundGray;
//some bit masks indicating whether the window is visible, is key etc.
}
-contentView;
-setContentView:aView;
//more methods
@end
请注意,contentView
ivar被定义为id
,并且访问者方法中的所有类型也被隐式定义为id
(所以-setContentView:
返回一个对象:可能是Window
实例self
)。这就是20世纪90年代早期大多数Objective-C代码看起来的样子:应用工具包可能是20世纪90年代早期的大多数Objective-C代码。
NSWindow
是在AppKit的第一个版本中引入的 - 1994年成为Cocoa的GUI框架.AppKit通常使用比Application Kit更严格的类型声明,但并没有严格遵守。实际上甚至可能是AppKit的NSWindow
包含来自Application Kit的Window
的代码,并且此contentView
ivar未在更改中更新。
事实上,Objective-C变量中对类型一致性的严格要求是相对较新的。大多数严格性是通过属性声明(除了C存在并且支持强制类型之外的强类型)或者通过更改允许可选方法的协议引入的,因此可以严格地键入委托对象。
答案 1 :(得分:2)
-[NSWindow contentView]
具有id
类型的事实可能是Cocoa和Objective-C早期的遗留。
无论如何:编译器警告是您用于发送消息的属性样式语法的结果。在Cocoa中(与Cocoa-Touch相对)window
,contentView
和frame
不是其类的属性。这意味着您应该使用正常的消息发送语法:
CGRect frame = [[[self window] contentView] frame];
这将在没有编译器警告的情况下工作。
答案 2 :(得分:-1)
用于动态输入。 NSWindow
如果它contentView
真的是NSView
,如果它响应发送的选择器,则NSView
并不在乎。所以,这样你理论上可以创建自己的类,它不会继承{{1}}来显示内容,编译器也不会窒息。