Why is the compiler requiring instance variable access over property access in class extension? - objective-c

The compiler in Xcode requires for me to use the instance variable name for a property declared in a class extension
#interface Person ()
#property NSString *bar
#end
#implementation Person
-(void) foo {
NSString *foo = _bar; // underscore required here
}
#end
In the code example above why can I not access bar without the underscore?

You can access bar as self.bar and it's more preferred than _bar. _bar is available for legacy code.
Looks like you came to Objective-C from Swift where the compiler adds self. for you automatically.

Related

Overriding a readonly property in subclass

There is a class that looks like this (I'm omitting the imports for brevity):
Base.h:
#interface Base : NSObject
#property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
#end
Base.m:
#implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
#end
As you see, the 'something' property is readonly. Now I want to create a subclass that overrides that property to be writable as well:
Sub.h:
#interface Sub : Base
#property (strong) NSString *something;
#end
Sub.m:
#implementation Sub
#end
And the code:
main.c:
int main(int argc, const char * argv[]) {
#autoreleasepool {
Sub *o = [Sub new];
o.something = #"foo";
NSLog(#"%#", o.something);
}
return 0;
}
This code results in:
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
Why is that? Why doesn't it find the setSelector?
When I do this in the subclass instead:
Sub.m:
#implementation Sub
#synthesize something = _something;
#end
it all works. Does this mean the subclass' property is not synthesized by default even though it is defined as #property in the #interface? Does the compile somehow 'see' the automatically generated getter from Base and doesn't generate the setter? And why, I think the setter should be generated as it doesn't exist yet. I'm using Xcode 4.6.2 and the project is a Cli Tool (type Foundation), but the same happens in my actual project which is an iPhone app.
Background: I have a heavy object (instance of Base) that requires a Bluetooth connection to some equipment and I am supposed to create a view controller for some functionality. For easy testing I don't want to be connected to BT (actually, I would need a physical device and test the code on it), I would like to be able to test it in the simulator.
What I came up with is that I simply create a subclass (Sub) that stubs a few methods / properties and use it instead, and when the code is ready I just remove the code for the subclass, replace its instance with the correct one, test in with a device, commit and push. It actually works fine, except for the weird thing with #property above.
Could somebody tell me what is going on with property overriding?
For a readonly property, only a getter method is synthesized, but no setter method.
And when compiling the subclass, the compiler does not know how the property is realized
in the base class (it could be a custom getter instead of a backing instance variable).
So it cannot just create a setter method in the subclass.
If you want to have write access to the same instance variable from the subclass,
you have to declare it as #protected in the base class
(so that it is accessible in the subclass), re-declare the property
as read-write in the subclass, and provide a setter method:
Base.h:
#interface Base : NSObject {
#protected
NSString *_something;
}
#property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
#end
Sub.h:
#interface Sub : Base
#property (strong, readwrite) NSString *something;
#end
Sub.m:
#implementation Sub
-(void)setSomething:(NSString *)something
{
_something = something;
}
#end
Your solution
#synthesize something = _something;
generates getter and setter method in the subclass, using a separate instance
variable _something in the subclass (which is different
from _something in the base class).
This works as well, you just should be aware that self.something refers to
different instance variables in the base class and in the subclass. To make that
more obvious, you could use a different instance variable in the subclass:
#synthesize something = _somethingElse;
The given answer works perfectly fine. This is an alternative answer, that apparently Apple likes a bit more.
You can define a private extension of your class, a Base+Protected.h file, which needs to be included in Base.m and Sub.m.
Then, in this new file, you redefine the property as readwrite.
#interface Base ()
#property (strong, readwrite) NSString *something;
#end
This alternative allows you to use the accessor self.something rathern than the ivar _something.
Note: you still need to keep the definition of something in your Base.h as is.
I guess that the backing variables are the same when the property is not synthesized in the subclass. So at runtime the programm tries to call the setSomething in the superclass. But since it doesnt exist there an Exception is thrown.

NSObject call to self gives XCode error

I have a class WebServices that inherits from NSObject. I am using xcode4.2 and ARC turned on.
When I created the class, there was no other method in the NSObject lie viewDidLoad or init.
The issues is that when I try to call self.something or [self someMethod] Xcode flags my code red and complains with:
implicit conversion of Objective-C pointer type 'Class' to C pointer type 'struct obj_class*' requires a bridge cast
Please help. Why isn't cocoa like java where you call "this" and get the object you are in?
// WebService.h file
#interface WebService : NSObject
#property (weak, nonatomic) NSString * myString;
+(void) setAndPrintMyString:(NSString*) someString;
#end
//WebService.m file
#import "WebService.h"
#implementation WebService
#synthesize myString=_myString;
+(void) printMyString:(NSString*) someString{
[self setMyString:someString]; //XCode does not allow
NSLog(#"myString is set to %#",self.myString); //XCode dose not allow
}
#end
Declaring a method with + means that it is a class method. Within a class method self refers to the class itself, which in your case would be [WebService class]. If you declared and instance method (using -) then inside the method self would refer to the instance, which is what you want.
To set an instance variable - you need an instance
WebService *webService = [[WebService alloc] init];
webService.myString = #"some string";
Now to make your method work you need to declare it with a - instead of + which makes it an instance method
- (void)printMyString:(NSString *)someString
{
[self setMyString:someString];
NSLog(#"myString is set to %#",self.myString);
}
Now
[webService printMyString:#"boom"];
results in the instance variable myString being set to boom and the console logging out `myString is set to boom".
viewDidLoad method doesn't fit with NSObject subclass. It's a method for UI which will be there in UIViewController subclasses.
Now, Coming to point about self.something OR [self someMethod], That works perfectly well with NSObject subclasses. You need to show us the code, in which you are facing problem.
Just for your reference (I think you should start developing for iOS after going through this):
NSObject Class Reference
UIViewController Class Reference

Singleton property access in objective C

I'm using a standard, modern singleton class with a singleton holding a CTFontRef, like so:
#interface MySingleton : NSObject {
CTFontRef paintingFont;
}
#property (readonly) CTFontRef paintingFont;
#end
#implementation MySingleton
+ (MySingleton*)sharedInstance
{
static dispatch_once_t once;
static MySingleton *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
//NB
sharedInstance->paintingFont =
CTFontCreateWithName(CFSTR("Helvetica"), 80.0, nil);
});
return sharedInstance;
}
#end
Then elsewhere I call [[MySingleton sharedinstance] paintingFont].
However, this call returns nil until I insert an underscore before paintingFont like so:
sharedInstance->_paintingFont =
CTFontCreateWithName(CFSTR("Helvetica"), 80.0, nil);
Why is this? Shouldn't the compiler require me to include the underscore? If not what is the purpose of the earlier version? And where did this underscore come in? I never declared the property with an underscore to begin with, I just see these seemingly random insertions of them into variable names in the debugger window.
Since Xcode 4.4, when you declare a #property, the compiler will automatically create an ivar for you and #synthesize the accessor methods. The default ivar is one with an underscore.
Using the -> syntax you access ivars directly and not the property. So, in your sharedInstance method you set your own ivar (without the underscore). However when you later try to access it, you use the [ ] which will use the automatically synthesized getter method to access your property (and the automatically generated ivar with an underscore).
You should use the . notation instead of the -> to access the property. Or simply use the automatically generated ivar called _paintingFont.
You can also make a property readwrite in your implementation file by adding the code below. This will allow you to use the dot syntax in your implementation to set the property, but still leave it readonly for other classes.
#interface MySingleton ()
#property (readwrite) CTFontRef paintingFont;
#end
If you want a different ivar, you can use #synthesize to override it. In both cases, you don't have to declare an ivar anymore.
#implementation MySingleton
#synthesize paintingFont;
....
#end
This is because in declaring a property paintingFont the Obj C compiler creates an instance variable _paintingFont.
In general the setting of a property/variable can either be done by
The instance as in your solution sharedInstance->_paintingFont = ...
Using the property and . notation sharedInstance.paintingFont = .... This calls the generated method setPaintingFont which then assigns to the instance variable.
However in this case the property is readonly so method 2 cannot be used.

Referring to Objective-C superclass variable

I have a base class with some variables defined that looks something like:
#interface Foo : NSObject {
SomeObject *baz;
}
#implementation Foo
#synthesize baz;
// ...
#end
#interface Bar : Foo
#end
#implementation Bar
-(void)someMethod {
NSString *foostr = [NSString stringWithFormat:"%#", baz];
}
I actually have a base class with about 30 subclasses.
The issue is that in most of them I can reference the base class' variable bad simply as baz but in a couple of sub-classes I have to explicitly reference bad as self.baz ...
Has anybody else seen this pathology?
If your compiler is set to gcc, there's a bug: A subclass that defines a #property without a corresponding ivar definition (which is perfectly legal) hides any superclass ivars.
Solution: Switch your compiler to LLVM.
(If that solution isn't feasible for some reason, the fallback is what you discovered: Use messaging instead of direct reference.)

If a subclass refers to a superclass ivar, synthesizing an unrelated property fails

Edit: I just noticed this other Stack Overflow question asking much the same thing: Why does a subclass #property with no corresponding ivar hide superclass ivars?
This is some interesting behavior that I cannot find documented in anything official or unofficial (blog, tweet, SO question, etc). I have boiled it down to its essence and tested this in a fresh Xcode project, but I can't explain it.
MyBaseClass has an instance variable:
#interface MyBaseClass : NSObject {
NSObject *fooInstanceVar;
}
#end
MySubclass extends MyBaseClass, and declares a totally unrelated property (that is, the property is not intended to be backed by the instance variable):
#import "MyBaseClass.h"
#interface MySubclass : MyBaseClass { }
#property (nonatomic, retain) NSObject *barProperty;
#end
If the implementation of MySubclass does not synthesize the property but implements the accessor methods, everything is fine (no compiler error):
#import "MySubclass.h"
#implementation MySubclass
- (NSObject*)barProperty {
return [[NSObject alloc] init]; // pls ignore flagrant violation of memory rules.
}
- (void)setBarProperty:(NSObject *)obj { /* no-op */ }
- (void)doSomethingWithProperty {
NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
NSLog(#"%#", array);
}
#end
But if I remove the property accessor methods and replace them with a synthesize declaration for the property, I get a compiler error: 'fooInstanceVar' undeclared (first use in this function).
#import "MySubclass.h"
#implementation MySubclass
#synthesize barProperty;
- (void)doSomethingWithProperty {
NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
NSLog(#"%#", array);
}
#end
This error goes away if I remove either the synthesize declaration, or if I do not refer to the fooInstanceVar instance variable from within MySubclass.m, or if I put all interface and implementation definitions in a single file. This error also seems to happen in both GCC 4.2 and GCC/LLVM build settings.
Can anyone explain what's happening here?
As replied in this question : objective c xcode 4.0.2: subclass can't access superclass variables "was not declared in this scope"
From the doc : Apple Objective-C Programming Langage :
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF125
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.
The compiler is behaving correctly; synthesis in a subclasss using storage in a superclass is verboten.
There was a bug about this filed against llvm at some point. It may be in the publicly accessible bug database.
In any case, please file a bug asking for clarification of this particular rule.
I just tried this and it compiles without warning. What am I not doing?
#interface MyBaseClass : NSObject {
NSObject *fooInstanceVar;
}
#end
#interface MySubclass : MyBaseClass { }
#property (nonatomic, retain) NSObject *barProperty;
#end
#implementation MyBaseClass
#end
#implementation MySubclass
#synthesize barProperty;
- (void)doSomethingWithProperty {
NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil];
NSLog(#"%#", array);
}
#end
It isn't clear what problem you are trying to solve. All instance variables are non-fragile everywhere but 32 bit Mac OS X.
I can't reproduce your error either. Do you have a non-default compiler flag set? Could you provide a copy of your project? It definitely appears to be a bug in the compiler.
Check out this article here for the best use of #property/#synthesize. A quick summary is to remove all of your ivars from your objects (unless you need to use the 32-bit runtime for some reason). Then only use your getters and setters, rather than accessing the synthesized ivars directly. Following this will avoid any future problems with this bug.