I just tried compileing my iPhone app against OS 3.0 and I get a compile error when using fast enumeration.
I'm trying to go through an NSArray containing cComment classes:
for (cComment* newComment in comments.comments)
And I get this error
error: type of accessor does not match the type of property 'comments'.
This works flawlessly when compiled with OS 2.2.1.
I understand the error, the enumaretion isn't strongly typed but since as far as I know generics/templates are not supported in objective-c. So currently I can only see one way around this:
for (id commentObject in comments.comments)
{
cComment *newComment = (cComment *)commentObject;
}
Can anyone think of another way? Why has this changed? Any points to apple documentation about this change would be appreciated.
EDIT
Following Grouchal suggestion i tried this:
NSArray* allComments = comments.comments
and I got the same error so it seems its not about the enumeration after all
here's the code form the header file:
NSMutableArray *comments;
#property (readonly,nonatomic) NSArray* comments;
and the property is synthesized in the implementation file.
Changing the property to NSMutableArray seems to solve the problem but I don't see any reason why this should be the case. Any ideas.
Thanks.
The problem is in the property definition. You should change have it as:
#property (readonly,nonatomic) NSMutableArray* comments
On the downside, your array will be exposed as mutable (though I suppose that's what you wanted to prevent).
I don't see any reason why this code shouldn't work in OS 3.0 I have similar code working already.
What happens if you change the code to
NSArray *commentArray = comments.comments;
for (cComment *newComment in commentArray){
.....
}
I've just noticed as I've written this where the * is in your code - is this the problem? should it really be cComment* in the for declaration?
I'm going to close this question and ask a new one under objective-c changes for iPhone OS 3.0.
I implemented the getter method myself to return an NSArray and it works just fine. Also changing the property to NSMutableArray works but it really isn't what I want to do.
I have no idea why this changed. This is an objective-c change and not an OS change. Also there is no mention of it in the documentation of changes between 2.2 API 3.0 API.
Thanks everyone for responding.
Related
I'm doing this tutorial (http://www.raywenderlich.com/1845/how-to-create-a-simple-iphone-app-tutorial-part-2) to get the hang of ios development, but now I'm stuck.
It's probably just a little thing, but when I get in my detailView's method 'setDetailItem', the newDetailItem variable is empty (see screenshot).
I have no idea why this is, but in the tutorial this seems to get automatically filled.
Why is it empty and how do I get the right detailItem?
I checked the tutorial and a sample code is provided by them.It works fine with the memory.It is a setter method which is called when you provide the value like this
DetailViewController *detailController =segue.destinationViewController;
ScaryBugDoc *bug = [self.bugs objectAtIndex:self.tableView.indexPathForSelectedRow.row];
detailController.detailItem = bug;
check weather you are passing in valid memory value (here bug).if you give it nil then yeah there may be no memory
I noticed a difference between the way I code (badly ;) ) and the code I see from others.
Can anybody explain why I see some people using
self.varname.anotherpropertie
When
varname.anotherpropertie
Seems to work just as well. I dont use self. a lot in my code. I'm wondering is this very bad or is there something that I need to learn to understand why its used so much by most people?
Thanks again,
-Code
They are different things. In a class where you have an instance variable named foo with a declared property also named foo, writing simply foo accesses the instance variable while self.foo goes through the getter method for the property (which might just return the instance variable or it might do more).
I'd suggest taking a look at the Declared Properties chapter of Apple's The Objective-C Programming Language for a full explanation of how it works and when to choose which option.
One gotcha that I've run into is the retain vs non-retain with properties.
So if you have a retained property like this:
#property (nonatomic, retain) NSString* myStr;
#synchronized myStr;
and you do something like this:
- (void) myMethod:(NSString*)inStr
{
myStr = inStr;
}
In this example you will not actually retain the string as your property is not invoked. If you change the assignment line to use the property (by using "self.") then the string would be retained (and the previous string would be released if non-nil).
self.myStr = inStr;
It takes some getting used to that properties are method calls, but once you start seeing them as such then the "self." syntax becomes much more clear. Hope that helps some.
I am currently working on an App which uses core data. I tried specifying CoreDataGeneratedAccessors in the interace itself, but accessors like setName do not seem to be automatically generated.
Is this something wrong with my XCODE configuartion?
Thanks,
Jith.
The generation of accessors by properties is a function of the language version and it is nearly impossible to change the language version in Xcode. In fact, I've never seen anyone with that problem.
You're most likely missing the #dynamic directive for the property in the implementation (.m) file. You need to have something like:
#implementation MyManagedObject
#dynamic propertyName;
... to get the accessors for managed objects.
I'm working on an existing, large-ish codebase, and after upgrading the iOS SDK to 4.1 I am now seeing very strange behaviour. The crux of the matter appears to be a particular class that will no longer alloc - it is throwing a bad access in obj_msgSend, and seems to be the Class object on the stack that objc_msgSend doesn't like - although it is not actually NULL.
The original failing line looked like this:-
tileProjection = [[RMFractalTileProjection alloc] initFromProjection:proj tileSideLength:sideLength maxZoom:18];
I deconstructed this to isolate the problem:-
RMFractalTileProjection *p = [RMFractalTileProjection alloc]; // <- this crashes
p = [p initFromProjection:proj tileSideLength:sideLength maxZoom:18];
tileProjection = p;
I then tried this:-
Class c = NSClassFromString(#"RMFractalTileProjection");
assert(c);
NSLog( #"RMFractalTileProjection class(ptr) %p", c ); // <- prints an address OK
NSLog( #"RMFractalTileProjection class(obj) %#", c ); // <- crashes
In the debugger it looks like the Class object is sensible, but NSLog crashes when it tries to print it.
One thing to note: the class in question is declared as below, and I'm not sure if the protocol is causing a problem. Because this particular part is a large chunk of open source code, it is very difficult to remove this protocol requirement to see if that makes a difference.
#interface RMFractalTileProjection : NSObject<RMMercatorToTileProjection>
{
...
}
Any help on this one greatly appreciated - it is a show stopper.
Thanks
This is not really an answer but some ideas to move forward.
The only causes that leap to mind at the moment are memory corruption and some sort of link issue. Perhaps you are linking two versions of the class somehow.
Assuming this is the class, there doesn't look to be anything wrong to make it crash in alloc. There's no +initialize or anything.
Questions I would be asking myself and trying to answer are:
what happens if I rename the class?
what happens if I create a new identical class with a different name?
the pointer that gets passed to obj_msgSend: is it reasonable? does it point to something that looks like a class?
do you ever subclass the class and do you use initialize on the subclass?
is the pointer always the same? If so you can watch what it points to and see if it changes during execution.
what happens if you send self to the class?
OK, finally found this. As Jeremy suggested, this turned out to be a regular memory stomper.
The difficulty I had finding it was that it wasn't the Class object itself that was getting stomped, but the class' metaclass structure - which is a normal Class object but one level up, referenced by the class 'isa' pointer. That's why the class looked OK to me when I inspected it in the debugger - I need to follow the isa pointer and dump memory at one level up to find this. Luckily for me, the class was only a subclass of NSObject - had it been deeply subclassed, this could have been much harder to find. I got my first clue after biting the bullet, reverse-engineering objc_msgSend, working out exactly what was on the stack frame, and following all the pointers. Yep, the hard way :)
Matt Gallaghar's post (and various others I found by following links) were invaluable in helping me through this maze - thanks guys!
Burned a lot of time on this one, but on the up side I learned a hell of a lot about Objective C internals during the past day and a half :)
Thanks for these suggestions JeremyP - it is always good to have fresh suggestions after you've been banging your head against the keyboard all day!
Your suggestion of creating an identical class with the same name appears to have fixed the problem. I have no idea why and I feel I need to understand what's going on here. You're right it sounds like some kind of linker issue, but I still have no idea what could cause such a serious runtime error and not even produce a warning at build time.
Re. the pointer, it does look reasonable, but something inside the class eventually gets dereferenced as a null pointer inside objc_msgSend. Occasionally, after I have changed the code and rebuilt, I get a null pointer instead. This behaviour obviously suggests something nondeterministic like a memory stomp.
I'll post my findings.
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
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.
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.