Question

When I tried compiling my app for OS 3 I encountered an the following error:

error: type of accessor does not match the type of property

The error was for a property I tried to access that is defined as follows:

NSMutableArray *myArray

@property (readonly,nonatomic) NSArray* myArray;

the property is @synthesized in the implementation file.

This worked just fine in OS 2.2.1 but doesn't is OS 3.0

Writing the getter method myself solved the problem.

Is anyone aware of changes to objective-c between OS 2.2.1 and 3.0? Is there any documentation for these changes?

The API changes document doesn't appear to contain anything about this issue.

EDIT

the error occurs when you try to access the property e.g.

NSArray *anArray = myClass.myArray;

As I mentioned above I found a workaround for this: writing the getter method myself, however what I'm really after is some kind of documentation from apple explaining this change and any other changes that are not API related.

Thanks for your help

Was it helpful?

Solution

This is a compiler bug.

Though you didn't specify it completely, I expect your code looks like this:

@interface Foo : NSObject {
    NSMutableArray *objects;
}
@property (readonly, copy) NSArray *objects;
@end

@implementation Foo
@synthesize objects;
@end

The compiler is, unfortunately, confused between the declaration of the objects property and the declaration of the objects instance variable. Remember that properties and instance variables are different things in Objective-C; a property can be backed by an instance variable, but it's really part of the public interface of a class.

You can work around this by changing your code to clearly separate the definition of the instance variable from the definition of the property, for example by prefixing the name of the instance variable:

@interface Foo : NSObject {
    NSMutableArray *_objects;
}
@property (readonly, copy) NSArray *objects;
@end

@implementation Foo
@synthesize objects = _objects;
@end

This way the compiler doesn't get confused about the property versus the instance variable in expressions like self.objects (which it shouldn't anyway, but apparently does).

Just to head off the inevitable response: Apple does not reserve the underbar prefix for instance variables. It's reserved for methods. Regardless, if you dislike the underbar, feel free to use another prefix.

OTHER TIPS

edit: Original answer removed after peer review found it lacking. Please read Chris Hanson's comments on the matter. I'm leaving the rest here because I think it is still valid.


Note that even if you declare the property type to be NSArray, the object returned is still an NSMutableArray, and the mutable methods are defined for it. Declaring the property in this way does not prevent someone from accidentally mutating the array.

If you want to be sure that the returned array is not mutable, you could declare the property as in your original example, and then roll your own accessor:

- (NSArray *)myArray { return [NSArray arrayWithArray:myArray]; }

Note that this would return an unretained NSArray. It would be up to the caller to take ownership of the object if it needed to persist.

You are seeing errors because XCode is now issuing warnings and errors for things it did not previously...

I would argue that it should be at most a warning to do what you are doing, I understand your attempt to present the array as immutable to the outside world but have it mutable inside the class. You may want to consider a different accessor with a different name, built to return the mutable array specifically.

It is still Objective-C 2.0; the compiler is just maybe a little updated with considering this kind of type changing an error. It pretty much should be an error. At least it should warn you that you likely don't mean what you wrote. Then you could cast stuff to make it not warn you, which you can't do with the @synthesize statement.

I just exactly pasted your code and a synthesize statement into my controller and I got no errors or warnings about it. It built fine. Now I set the base SDK to "Simulator 3.0", and the build to "Simulator 3.0 Debug". This project had started in the 2.2.1 SDK and I just installed the 3.0 SDK yesterday; Xcode is version 3.1.3.

Update: Oh I see that actually trying to set the property is where you get the error you mentioned.

    self.myArray = [NSArray arrayWithObject:@"foo"];

Clearly you cannot @synthesize this behavior and must write your own accessors.

- (NSArray*)myArray {
    return [NSArray arrayWithArray:myArray];
}
- (void)setMyArray:(NSArray*) pMyArray {
    myArray = [NSMutableArray arrayWithArray:pMyArray];
}

Filling in these accessors, did not make the message go away, so I had to change the access to:

    [self setMyArray:[NSArray arrayWithObject:@"foo"]];

Using the above syntax without custom accessors also did not work.

PS Wow, is anyone else annoyed that you can neither copy message bubbles, or the text in the build results window?

So this is really to do with the @synthesize call that is not happy about exposing a NSMutableArray as an NSArray - why not just implement the getMethod.

Actually thinking about it it must be the set method that is not happy - you wouldn't be able to set an NSArray into an NSMutableArray.

Your questions were:

Is anyone aware of changes to objective-c between OS 2.2.1 and 3.0?

Is there any documentation for these changes?

The definitive answers are:

1) There were no intentional changes to the language specification, but the compiler and other developer tools changed. Chris and his coworkers are the experts on those changes.

2) Probably not, because any changes were unintentional or made to better match behavior with the documentation.

You shouldn't be so quick to dismiss Chris' answer as "a guess." Chris works on Apple's developer tools. You might get another answer you like more, but you won't be getting a more expert answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top