views:

1154

answers:

9

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

A: 

I've had no problems transitioning my Objective-C code from 2.2.1 to 3. Can you include more of your code? I'm fairly certain the Objective-C version didn't change.

Dan Lorenc
+5  A: 

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.

e.James
As I mentioned I did write the getter method myself and it did the trick. Thanks
Ron Srebro
Well, I'm pretty sure that makes this an answer, Ron.
Rhythmic Fistman
Actually it's not an answer it's a workaround, and as I mentioned in the question I already found a workaround. What I'm looking is an explanation why this worked in 2.2.1 and doesn't anymore and preferably the where this is documented.
Ron Srebro
@Ron Srebro: I agree with you. I definitely didn't answer your question about where the documentation could be found. I have a feeling that your original code (that worked in 2.2.1) would still throw a warning in 2.2.1, and you may not have noticed it, since it wasn't an all-out error (see Kendall Helmstetter Geln's answer). If your old code did not throw a warning, I would call that a bug in the 2.2.1 implementation of Objective-C, since the property type did not match the type of the ivar. If that is the case, it explains why there is no change documentation. They simply fixed the bug in 3.0
e.James
@eJames: Well it didn't give out any warnings in 2.2.1 so you might be right and for them it's just a bug fix. The more I dive deeper into iPhone development i find more and more documentation missing and it's a real shame. Developer support, documentation and tools is really something apple should learn from Microsoft. Thanks anyway, appreciate the advice.
Ron Srebro
@eJames: I started digging a bit in the iPhone OS 3.0 SDK download release note and I understand correctly they did released a new version of the compiler, so this might be the reason. I tried using the previous one to test I didn't even manage to get a test projected compiled at all. In any case as I said before I just would like to see the docs.
Ron Srebro
@Ron Srebro: Some of the Apple documentation can be hard to find (if it exists at all). Maybe it is because of the pace with which they innovate? I don't know, but the thought of Apple taking cues from Microsoft scares me :). Sorry I couldn't be of more help.
e.James
@eJames: You're incorrect, it's perfectly valid to have a property of type (NSArray *) backed by an instance variable of type (NSMutableArray *). This is just a bug.
Chris Hanson
@Chris Hanson: I was all set to argue, but having looked at your profile, I'm pretty sure you are better qualified than I am :) Thank you for setting the record straight.
e.James
+4  A: 

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.

Kendall Helmstetter Gelner
A: 

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.

Grouchal
While the problem may arise from the @synthesize, the fast enumeration calls the getter, not the setter, so the error still seems a bit out of place.
Quinn Taylor
moreover the property is marked as readonly so there's actually no setter method at all.
Ron Srebro
yes I'd forgot that - so the problem is just with @synthesized getters
Grouchal
+1  A: 

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?

dlamblin
I'm really annoyed about not being able to copy messages or the text. If anyone can find a solution for that, that will be great. In any case as I said the property in my case is read only so no problem in representing it as NSArray, and when I write my own getter method it works with no errors.
Ron Srebro
Horizontal slider (at bottom of top section) of build results window has icon with lines of text (next to checkmark and warning sign). If you click it, you'll get raw, copyable log.
porneL
@pormeL thanks for the tip. Very helpfull
Ron Srebro
+17  A: 

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.

Chris Hanson
Hi Chris. Actually I did specify the entire relevant code, moreover your suggestion for readonly, copy property doesn't make any sense and I doubt the compiler will let it go. I keep getting a sense her that people don't actually read the questions which is a shame because I was excited about this site for about three days.And you didn't answer my question which was why it used to work and isn't now, and point to some documentation from apple about it.
Ron Srebro
Ron, you just had a bare variable declaration, not an ivar declaration in an @interface. Furthermore, (readonly, copy) will work and is perfectly sensible: It says the property uses the "copy" style of memory management, and in this class is read-only. (A subclass could override that.)Finally, I restate that it worked prior to the iPhone OS 3.0 SDK and doesn't work in the iPhone OS 3.0 SDK specifically due to a compiler bug. You can read "The Objective-C 2.0 Programming Language" yourself to see what the behavior of the language should be.
Chris Hanson
Ron, what you posted in the question is definitely not the actual code you are using, as there are syntax errors in it that would prevent it from compiling (the first line requires a semicolon). What Chris is guessing is the only the sensible thing, if you are doing something truly exotic you need to post the actual code.
Louis Gerbarg
And BTW - trust me when I say, Chris knows what he is talking about.
KiwiBastard
@Kiwi - I'm sure Chris knows what he's talking about, however it still doesn't answer my question. @Louis - Of course I didn't post my entire code I just posted the problem with all the relevant details, there was no need to guess anything (aside from adding a semicolon). Writing it off as a compiler bug is not an answer its a guess and pointing me to the objective-c language reference isn't really an answer either.
Ron Srebro
@Chris, no doubt you wrote a very detailed answer, which would have helped me greatly if I didn't already have a solution to that specific problem. In a sense you gave me a good answer for a question I didn't ask. The only relevant part of your answer to my question was that it's a compiler bug, and for me thats not a very good answer. I hope take this in good spirit, I am just trying to clear my point. In any case thanks.
Ron Srebro
How is the truth not a good answer?
Chuck
Ron, it's not a guess.
Chris Hanson
Ok Chris given your insistence and the universal support for you on the site I'll take your word for it. Thanks
Ron Srebro
It is a bug (<rdar://problem/6083666>) and there was nothing about your description that indicated that it was anything but exactly that bug. There is no "take your word for it", Chris's description was precise.
bbum
Note that the bug is fixed in the compiler found in Snow Leopard, if you have access to the seeds. The compiler for the iPhone is sometimes slightly out of sync.
bbum
bbum, I'm pretty new to mac development or macs for that matter, so I really had no idea where to look for, the fact that you can't point to a documented bug is exactly what I looked for. All I asked was to find some documentation about it. If chris is saying it's a bug (with no references) all I can do is either take his word for it, or dismiss it as a guess (which I did at first).Can you post a link to the bug's documentation?And thanks your comments is exactly the answer I was after.
Ron Srebro
As I've said, you can look at "The Objective-C 2.0 Programming Language" to see how the language is designed to behave. Apple's bug database is not public.
Chris Hanson
A: 

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.

Peter Bierman
Thanks pbm. Noted and I accepted Chris's answer
Ron Srebro
A: 

im getting the error on iOS4 which i didnt get on 3.1.3. This is my code:

IBOutlet UIButton *calendarize; @property (nonatomic, retain) IBOutlet UIButton *calendarize; @synthesize calendarize;

gives me this warning:

type of accessor does not match the type of property

Mars
A: 

just found my problem! hate it when that happens: 2 minutes later:

i had an IBAction with the same name in the same class!

Mars