我今天正在制作一个程序并且遇到了这个奇怪的错误。我有一个分配了动作的UIButton。行动就像:
-(void) someaction:(id) e
{
if ([e tag]==SOMETAG)
{
//dostuff
}
}
令我困惑的是,当我第一次写它时, if 行是
if (e.tag==SOMETAG)
XCode拒绝编译它,说
error: request for member 'tag' in 'e', which is of non-class type 'objc_object*'
但我认为两者是等价的。
那么在什么情况下他们不一样?
答案 0 :(得分:5)
仅当变量具有声明的关联属性,或者存在可用的符合键值编码的访问器方法时,才可以使用点表示法。属性语法允许您为符合键值编码的变量“合成”访问器方法,实际上,这就是点符号的工作方式。
声明属性时,someObject.variable
相当于[someObject variable]
。
当对象键入为id时,编译器不知道该对象具有的任何属性。 id是指向任何对象的指针,实际上是void *。
您可以将对象转换为您期望的类型,这样您就可以使用属性语法。
((MyObject*)e).tag
答案 1 :(得分:2)
这里似乎存在一些关于属性和点符号的误解。点表示法可以与任何访问器方法一起使用,无论是否声明为属性,前提是编译器知道点左侧的对象具有访问器。您不需要使用@property
语法。您不需要合成访问者。以下是完全有效的Objective-C,可以干净地编译:
#import <Cocoa/Cocoa.h>
@interface AClass
{
}
-(NSString*) aProperty;
@end
@implementation AClass
-(NSString*) aProperty
{
return @"some text";
}
@end
int main()
{
AClass* foo = [[ACLass alloc] init];
NSLog(@"%@", foo.aProperty);
return 0;
}
关键点是编译器必须知道对象是否存在访问者,这意味着对象必须正确键入(即不能是id)。
答案 2 :(得分:1)
您可以使用提供的obj.prop getter语法(handwavily)编译器具有方法调用[obj prop]的原型,并提供setter语法[obj setProp:blah]。这意味着您可以将它用于NSNumberFormatter这样的类,它们不声明属性。这是否可取是值得商榷的。
如果您不介意所有括号,可以使用((Foo *)obj).prop将其强制转换为正确的对象类型。
请注意,未知方法的返回类型默认为id(因此您可能将id与int进行比较),并且您的发送方可能不是UIView(它可能是UIBarButtonItem)。如果您认为if ([(id<NSObject>)e isKindOfClass:[UIView class]] && [(UIView*)e tag] == sometag)
符合&lt; NSObject&gt;,那么e
会更安全一些。
答案 3 :(得分:0)
您不能在id对象上使用点表示法。这只是他们的规则。
答案 4 :(得分:0)
这是杰克在我评论之前删除了他的答案: - )
您不是直接访问实例变量,点符号仅用于通过@synthesized的getter和setter方法获取属性。您正在向对象发送消息,在这种情况下会导致调用这些getter / setter方法。您不能使用点表示法直接访问成员变量,也不能直接调用方法 - 必须将其设置为属性。