Objective-C, properties for references - iphone

This might be iPhone specific, I'm not sure. The compiler doesn't complain when building for the simulator but when compiling for device it throws some funky errors when I try to set properties for references to objects. Eg,
#property (nonatomic) CGRect &finalFrame;
and the coressponding synthesizer
#synthesize finalFrame;
for a variable declared as
CGRect finalFrame;
Gives the errors
type of property 'finalFrame' does not match type of ivar 'finalFrame'
Unrecognisable insn:
Internal compiler error: Bus error
Internal compiler error: in extract_insn, at recog.c:2904
However I can do it manually without issue, with the following methods:
- (CGRect&)finalFrame;
- (void)setFinalFrame:(CGRect&)aFrame;
Is this a gcc bug? It does compile for the simulator.

Your property is declared as a reference type (CGRect&) but your instance variable is not a reference type (CGRect). They need to be the same to use #synthesize.
Also, it's a little weird to be using C++ reference types as Objective-C properties, but I guess that might work as long as all the files are being compiled as Objective-C++.

Related

Why is this code giving me an error about a weak property?

This is my simple piece of code on iOS, using ARC:
#interface Person : NSObject {
NSObject *objStrong;
NSObject *objWeek;
}
#property(strong) NSObject *objStrong;
//getting error at this line
#property(weak) NSObject *objWeek; //Existing ivar 'objWeek' for _week property 'objWeek' must be _week
#end
#implementation Person
#synthesize objStrong;
#synthesize objWeek;
#end
When I try to compile, the compiler complains about an existing ivar 'objWeek' for _weak property 'objWeek'. Why isn't this code compiling correctly?
It's complaining because the backing variable, NSObject *objWeek is declared as __strong (all otherwise unannotated Objective C pointers to retainable objects are __strong). Change the backing variable to be __weak NSObject *objWeek, and the compiler will like you again.
Edit: As requested, the ARC documentation from LLVM's clang:
4.4.1. Objects
If an object is declared with retainable object owner type, but
without an explicit ownership qualifier, its type is implicitly
adjusted to have __strong qualification.
As a special case, if the object's base type is Class (possibly
protocol-qualified), the type is adjusted to have __unsafe_unretained
qualification instead.
Link: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.inference
Same problem I have faced. I did spend lot of time on this finally I could solve this problem by cleaning the project.Here is the way....
product->clean
The reason is you may be deleted controller class(ViewController) but still it is not removed from your project.when you finish cleaning of your project the error will be gone automatically. This worked for me...

ARC forbids Objective-C objects in structs or unions despite marking the file -fno-objc-arc

ARC forbids Objective-C objects in structs or unions despite marking the file -fno-objc-arc?
Why is this so?
I had the assumption that if you mark it -fno-objc-arc you don't have this restriction.
If you got this message try __unsafe_unretained. It is only safe, if the objects in the struct are unretained.
Example: If you use OpenFeint with ARC the Class OFBragDelegateStrings says this error in a struct.
typedef struct OFBragDelegateStrings
{
NSString* prepopulatedText;
NSString* originalMessage;
} OFBragDelegateStrings;
to
typedef struct OFBragDelegateStrings
{
__unsafe_unretained NSString* prepopulatedText;
__unsafe_unretained NSString* originalMessage;
} OFBragDelegateStrings;
Rather than using a struct, you can create an Objective-C class to manage the data instead.
That is because arc can't track objects in structs or unions (since they are at that point plain C pointers).
Even though you marked the file/class in question with -fno-objc-arc you might still pass an object controlled by arc to it as parameter, which would most likely result in a memory leak.
Looks like this now works without errors, probably after this change.
i.e., You can put normal (strong) pointers to Objective-C objects in a C struct. It is managed by ARC e.g., it is unretained when the struct is destructed. Verified with:
$ clang --version
Apple LLVM version 10.0.0 (clang-1000.11.45.2)

objective c xcode 4.0.2: subclass can't access superclass variables "was not declared in this scope"

I have several classes that are subclasses of one Layer class.. for some reason one of the subclasses acts differently. this is a stripped down version:
#interface Layer: CCLayer
{
GameScene* _scene;
CCNode* _layerNode;
}
#end
#import "Layer.h"
#interface UILayer: Layer
{
}
#end
#implementation UILayer
-(void) doStuff
{
[_layerNode addChild:[CCNode node]]; <---gives compile error: "_layerNode was not declared in this scope"
[_scene playSound];<------gives compile error: "_scene was not declared in this scope"
}
#end
I think that gets the basic idea across. I can fix this by doing
[[_self _layerNode] addChild:[CCNode node]];
[[_self _scene] playSound];
but what I can't figure out is why other subclasses of Layer can access _layerNode and _scene directly? I am guessing that it is a problem with the build settings. Further this problem only happens when I build it for the device (iphone) and not the simulator. let me know if you need more information to answer.
Edit:
Oops I wrote it wrong. It should have been [[self _layerNode] addNode:[CCNode node]] but I guess the question is why would one subclass have direct access to the ivar _layerNode and another have to access it with [self _layerNode]. It is like the UILayer can't find the super class header
From the docs: Apple Objective-C Programming Language (doesn't mention this anymore, but you can find it in this retired document).
The instance variable is accessible within the class that declares it and within classes that inherit it. All instance variables without an explicit scope directive have #protected scope.
However, a public instance variable can be accessed anywhere as if it were a field in a C structure. For example:
Worker *ceo = [[Worker alloc] init];
ceo->boss = nil;
I have the compilation error using LLVM GCC 4.2 (for an iOS project, on device):
error: 'fooInstanceVar' undeclared (first use in this function)
and the same one using GCC 4.2 :
error: 'fooInstanceVar' undeclared (first use in this function)
I can compile using LLVM Compiler 2.0 whithout error.
For compiling with LLVM GCC 4.2 and GCC 4.2 with the use of self->:
[NSArray arrayWithObjects:self.barProperty, self->fooInstanceVar, nil];
in the doSomethingWithProperty method.
Maybe it's the name. The 'UI' prefix is designated for UIKit classes. Could well be that UILayer is a private UIKit class used by Apple.
If you #synthesize ivars, the compiler unhelpfully stops you from accessing them "directly". The fix is relatively easy: Write self->_layerNode and self->_scene.
I'm assuming your "stripped-down version" compiles fine.
Note that it's also bad form to directly access your superlcass's ivars unless you're aware of its implementation details.
(What's _self?)

Should get 20 errors... but get 0... when compiling without declaring an instance variable

In my iPhone apps I regularly do this in xCode v3.2.3:
Declare a BOOL variable in the *.h file
Use #property in the same *.h file.
Use #sythesize in the matching *.m file.
I accidentally forgot to do #1... but it still complied fine. 0 warnings. 0 errors. 0 analyzer errors.
How can that be? Shouldn't my code to loaded with compiler-errors everywhere that variable is trying to be used?
This is a feature of the new runtime. See this question for more details.
Automatic synthesis of instance variables (ivars) is a feature of the Objective-C 2.0 runtime on OS X and of the new iOS Objective-C runtime. The #synthesize directive will automatically create the necessary ivar at runtime unless you have declared it yourself. This is made possible by Objective-C 2.0's non-fragile ivar support. Thus, there is no error and you should not receive them.
Ultimately, it's a good thing that you don't have to declare ivars in the interface of a class. They are (probably) implementation-specific details which you don't want to have visible as part of the public interface of the class. Note that using class categories you can also automatically synthesize ivars for "private" properties as well.

Objective-C changes between OS 2.2.1 and OS 3?

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.