Objective c 财产'';在类型为';id';

Objective c 财产'';在类型为';id';,objective-c,cocoa-touch,properties,Objective C,Cocoa Touch,Properties,尝试读取或写入数组中的aVariable时,在id类型的对象上找不到属性“aVariable”。难道不应该知道我添加的对象是什么类吗?还注意到它可以使用NSLog(@“%@,[[anArray objectAtIndex:0]aVariable])读取值 我是Objective C的初学者,所以这可能是我不懂的一些简单的东西 对象 另一个物体 测试h test.m -[NSArray objectAtIndex:返回一个id指针。由于id不包含有关协议的信息,编译器无法知道对象具有您声明的此属性

尝试读取或写入数组中的aVariable时,在id类型的对象上找不到属性“aVariable”。难道不应该知道我添加的对象是什么类吗?还注意到它可以使用
NSLog(@“%@,[[anArray objectAtIndex:0]aVariable])读取值

我是Objective C的初学者,所以这可能是我不懂的一些简单的东西

对象 另一个物体 测试h test.m
-[NSArray objectAtIndex:
返回一个
id
指针。由于
id
不包含有关协议的信息,编译器无法知道对象具有您声明的此属性;这就是它抱怨的原因

您可以通过强制转换objectAtIndex:的返回值或使用getter/setter表示法来解决此问题,即
[anArray objectAtIndex:0]setAVariable:…]
。还要确保导入协议定义,否则编译器可能也不知道声明的方法,并发出警告。

此代码:

[anArray objectAtIndex:0].aVariable
可分为两个部分:

[anArray objectAtIndex:0]
这将返回一个
id
——因为您可以将任何类型的对象放入数组中。编译器不知道此方法将返回什么类型

.aVariable
这是在从数组返回的对象上请求属性
aVariable
——如上所述,编译器不知道这个对象是什么——它当然不会假设它是一个
AnObject
,因为这是您之前添加的一两行内容。它必须单独评估每个语句。因此,编译器会给出错误信息

当使用访问器方法时,它会更宽容一些:

[[anArray objectAtIndex:0] aVariable];
这将给您一个警告(对象可能不会响应选择器),但它仍然允许您运行代码,幸运的是,您的对象确实响应该选择器,因此不会发生崩溃。然而,这并不是一件安全的事情。编译器警告是你的朋友

如果要使用点表示法,则需要告诉编译器从数组返回的对象类型。这叫做铸造。您可以分两步执行此操作:

AnObject *returnedObject = [anArray objectAtIndex:0];
int value = returnedObject.aVariable;
或者用一堆括号:

int value = ((AnObject*)[anArray objectAtIndex:0]).aVariable;
int value = [(AnObject*)[anArray objectAtIndex:0] aVariable];
需要额外的括号,以便在铸造时使用点符号。如果要使用访问器方法,则需要更少的圆括号,但需要更多的方括号:

int value = ((AnObject*)[anArray objectAtIndex:0]).aVariable;
int value = [(AnObject*)[anArray objectAtIndex:0] aVariable];

为了完整性,应该注意,dot语法最终也使用了accessor方法。问题是,除非对象的类型已知,否则编译器无法确定属性的访问器是什么,因为访问器可以有任何名称(
@property(getter=numBananas)int-numaples;
,例如。)。+1,用于在使用点表示法时注意强制转换的需要。(在我的情况下,对象类型是在运行时确定的,我只是避免使用点表示法。)
int value = ((AnObject*)[anArray objectAtIndex:0]).aVariable;
int value = [(AnObject*)[anArray objectAtIndex:0] aVariable];