I've been running into this problem a lot lately. I have an NSMutableArray
called tests
which is populated with instances of my custom class Test
. I'm trying to access a property with the following method:
return [tests objectAtIndex:row].name;
However LLVM always throws an error and refuses to compile:
error: Semantic Issue: No member named 'name' in 'struct objc_object'
How do I tell the compiler that I'll be accessing a Test
object and to l开发者_运维百科et me compile the damned thing?
In order to use the dot notation for properties, the compiler needs to know the object's type.
You can send a message:
return [[test objectAtIndex:row] name];
Or you can cast the value returned by objectAtIndex:
:
return ((Test*)[tests objectAtIndex:row]).name;
You might wonder why. The compiler needs to know the object's type because a property can designate any method to be the getter or the setter, not just the default pair of name
and setName:
, for example, this is usual with BOOL
properties:
@property(getter=isEditable) BOOL editable;
So the compiler needs to know what property this is in order to generate the correct accessor calls.
Since objectAtIndex:
returns id
, that is, a generic pointer, the compiler can't possibly know what method name to substitute for your property access .name
.
You have to completely specify to the compiler what you want to do in this case. Either specify the exact method name:
[[tests objectAtIndex:row] name];
or specify the actual type of the object:
((Test *)[tests objectAtIndex:row]).name;
When you write foo.bar
, the compiler has to look in foo
's class and find the method names associated with the property bar
. Those are usually bar
/setBar:
, but they could be anything;* because of that ambiguity, the compiler needs to know the actual class of foo
. Given only a generic pointer, it can't find that information.
The warning indicates that the compiler also checked whether the object on the left side of the .
is a struct with a field called name
. There isn't such a field, so the compiler does not know what you want it to do.
*E.g.,
@property(retain, setter=putThisValueIntoBar, getter=hamAndEggs) Bar * bar;
Adding an explicit cast should do the trick.
Test *test = [tests objectAtIndex:row];
test.name
Or send a message instead of calling a method.
[[tests objectAtIndex:row] name]
Or you can caste it like this:
return ((Test*)[tests objectAtIndex:row]).name;
精彩评论