I have to expose a private property to sub-classes.
Since there is no such thing as "protected properties" in objc AFAIK, I'm using the #protected directive to expose the corresponding ivar that's synthesised by the complier.
This method appears to work, however, I'm not sure if I'm affecting the synthesis of the property and ARC in some inadvisable way?
I'm using a weak property here to show how the compiler forced me to use __weak modifier with the #protected directive, i.e. it appears the complier is aware of the two declarations and the link between them.
Superclass .h file
#interface Superclass : NSObject
{
#protected
SCNScene * __weak _scnScene;
}
#end
Superclass .m file
#interface Superclass ()
#property (weak, nonatomic) SCNScene * scnScene;
#end
#implementation Superclass
........
#end
Subclass .m file
#implementation Subclass
// Can use _scnScene just fine
_scnScene = .....
#end
Yes, it'll probably work. Don't do it this way. It's very inflexible. It forces you to declare ivars in the header, it only works with ivars, and it doesn't give you any control over read/write controls (or let you create a custom getters/setters). There isn't really a good reason to use the # access controls anymore (not since the move to non-fragile ivars, and they weren't that useful before).
A typical way to do this is with a +Protected header with a category. For example, you'd create a header file Superclass+Protected.h like this:
#interface Superclass (Protected)
#property (weak, nonatomic) SCNScene * scnScene;
#end
Then you import that into any implementation files that are allowed to access scnScene. Note that you could make this readonly if you wanted, so internally it's writable, but to protected implementations it's only readable, and to the public, it's invisible.
This is more flexible than literal "protected" because you can import this header into any other implementation where it is appropriate. So it can also be the equivalent of C++'s "friend." Obviously naming the file and providing some header comments can be helpful to let callers know if they should or shouldn't import this file.
To any complaints that this doesn't enforce access controls (not that you made any, but for anyone that does), neither does #protected. If I call valueForKeyPath:, I can access protected ivars, too. ObjC helps you create "no trespassing signs" so that callers know when they're in places they shouldn't be. It doesn't try to stop programs from accessing their own memory space. (This would be a futile goal; you can always read private variables and call private functions in any language that allows raw memory access; the point of access controls is to help callers write correct code, not stop them from doing anything.)
In the context of a class declaration, protected is the default visibility for instance variables, so your declaration has no effect. In fact, the following declaration:
#interface Superclass : NSObject
#end
would have the precisely the same effect as the declaration you posted, because the compiler automatically synthesizes any needed ivars for declared properties, unless you declare them yourself.
Related
May I know what is the difference between instance variable in .h file and property in .m file in objective c?
I know that both cannot be used outside the class. Any other difference?
A. You can add ivars inside the implementation, too:
#implementation AClass
{
id ivar;
}
Therefore the difference is not that ivars has to be in the header (interface). (But see below B.)
B. If an ivar should not be used outside, there is no reason to put it in the public header. Why do you want to inform somebody about an ivar, if he cannot use it? This is source code spamming.
C. A property adds (or uses) an ivar. Additionally it adds accessor methods.
D. A property provides additional semantic information, especially about atomicity and setter semantics, if it is declared in the header.
Up to here it should be clear that properties are usually the better way to model an object state. So why do we have ivars in headers?
This is for legacy. In former times we did not have declared properties. There has been some reasons for having ivars in the header (for example to tell the compiler the object size), but this are gone. The only meaning for declaring ivars in the header in nowadays is that you make them public and let others access them directly for performance reasons. You should have very good performance reasons to do so. I had never had them.
In addition to Jef's answer:
If you want to make ivars public to subclasses, you can put them into a class continuation in an extra file. Let's have an example:
MyClass.h
// We do not put ivars in the public header. This is an implementation detail.
#interface MyClass : NSObject
…
#end
MyClass_SubclassAddition
// We do put ivars in an extra header with a class continuation, to make them visible for subclasses
#interface MyClass()
{
id ivar;
}
#end
MyClass.m or MySubclass.m
// We use both headers in the implementation and subclass implementation:
#import "MyClass.h"
#import "MyClass_SubclassAddition.h
#implementation MyClass
…
#end
You can get rid of the "subclass ivar problem", if you use setters in initializers. Whether this is wrong or not to do so, is a different discussion. Personally I prefer to use setters. But do not let us start that discussion again (and again and again …)
the biggest practical difference is that subclasses can see and use ivars which are declared in the .h, where if they are in an extension at top of the implementation file a subclass cannot access them.
I like to start with them in the .m file but i'll happily move one to the header in order to use it from a subclass.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iOS: must every iVar really be property?
I just read a book that said that modern convention is not to declare any ivars at all in your .h file between curly braces, and instead to make everything properties.
I want to make sure this is true even in trivial cases. I am making a class where there is a BOOL named "recording" which says whether the device is currently recording some video. This isn't something that other classes need, and my incline is to just put it as a BOOL in the header then refer to it in the .m file in the 2 spots where it is needed.
However, I also want to do things the accepted, right way. But I don't see why I make it a public property?
What you read is wrong, plain and simple.
Modern convention is to skip ivars when there is a corresponding property that can synthesize them. Additionally, with recent versions of LLVM it is possible to move your ivars to your implementation file (as #DrummerB has already mentioned) so that the header contains no ivars. That's considered good practice because it doesn't expose internal workings of the class.
But have no ivars at all and a property for everything that was an ivar? Nope, not normal Objective-C.
Your book is right (and wrong). Don't declare ivars in your headers anymore. That's only supported for compatibility reasons. But also don't declare properties for private variables.
If you want do declare a private ivar that other classes don't need to use, declare them in your implementation file:
// MyClass.m
#implementation {
BOOL recording;
}
// methods
#end
I recommend to not use ivar at all. Instead you can create a class extension in which you will declare properties that has to be hidden:
#interface MyClass ()
#property (nonatomic, assign) BOOL recording;
#end
You could use something like
#interface G4AppDelegate ()
#property (nonatomic, assign) BOOL recording;
#end
To make an "internal" property.
Or as the other answer states use an iVar in your implementation
Some books explain that you should only use getter and setter to access your ivar, even if they are private. This is a little too psychotique to me.
Before clang, u should have to create category on class and use synthesizer to make ur ivar private. like this:
#interface AppDelegate ()
#property(nonatomic, assign)int aValue;
#end
// + #implement AppDelegate
// #synthetise aValue;
that could be annoying since sometime u need some simple ivar, without any getter/setter control. And u're adding code where there is no need.
Now with clang you can put ur ivar directly on implementation file like this in ur code:
#interface AppDelegate (){
int _aValue;
}
#end
And u're hiding private ivar out of the scope the header.
Note, u can't compile this with gcc.
I am confused as to why some classes declare a property but do not declare an ivar and vice versa.
Is it standard practice when declaring an instance variable to also declare it as a property as well?
Example:
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
is just standard practice when declaring a class's ivar to make it a property as well?
I get that the #property creates its own elongated setter (and getter with #synethesize) but why does it need to be an ivar as well?
It doesn't.
In the old days, ivars were required to be declared in the #interface. This is actually still true for PPC and i386 (i.e. 32-bit intel) targets. This is because of the fragile base class problem, which required that all subclasses know the exact size of their superclass. As such, ivars need to be in the #interface or nobody can subclass the class.
With the move to x86_64 and ARM, alongside obj-c 2.0 came a fix for the fragile base class problem. With this fix, class sizes no longer need to be known at compile time but can be deferred to runtime. Therefore, ivars can be declared in other places. Notably, an ivar can now be synthesized from a #property (more specifically the #synthesize line in the implementation). In Clang they can also be declared in a class extension block (which looks like #interface ClassName ()) or directly on the #implementation.
Today, there are 3 reasons why you find ivars declared in #interface blocks:
Old code (or programmers with old habits) that hasn't been updated to take advantage of the ability to hide ivar declarations.
Code that needs to run on PPC or i386.
Code that, for whatever reason, wants their ivars to be public. This should never be the case.
When writing code today that doesn't need to target the old runtime, you should either synthesize your ivars from your properties (preferred), or if you need ivars that aren't tied to properties you should declare them in a class extension or on your #implementation. The primary reason for this is because the header file documents the public API of your class and should not contain anything that's not public. Ivars are not public, and therefore should not be in the header file.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Synthesized property and variable with underscore prefix: what does this mean?
The usage of Objective-C properties has always felt awkward to me. It's one of the "I know how to use them, but I'm not always sure why I'm using them." kind of things and recently I've been seeing a lot of this:
// in .h file
#interface MyObject : NSObject
{
id _coolIvar;
}
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;// <- whats the point of that.
#end
So what is the point of declaring an ivar with an underscore and then using #synthesize to access it, Opposed to just declaring the #property with the same name as the ivar?
Side Question:
I've noticed that this convention has been becoming increasingly more popular since blocks started becoming the preferred approach for async callbacks opposed to the target/selector approach. Is that a coincidence or does the above #property declaration convention play nicer with block scopes?
It's preference.
It's also my preference to not declare the variables twice and just let them be synthesized like:
// in .h file
#interface MyObject : NSObject
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;
#end
The two reasons I like to use the _ prefix is
I know when I am going through an accessor and when I am accessing the variable straight.
If it makes sense for me to call an ivar address it is more than likely that inside a method a similar variable would also be logically called address. If my ivar does not have an _ prefix then my local address will mask the ivar address.
I also like how xcode will autocomplete vaiables starting with an _ when you start typing your #synthesize myVar = _...
NB
You may run into the odd name clash (I have only once) but the warning that the complier gives you makes it a pretty easy spot and simply changing the name is a quick win.
#isaac touched on not declaring ivars so that they are not publicly advertised but does not explain how/why. Basically you can declare #property's in a class extension to still give you the benefits of the #synthesized getter/setter but without making your public API look ugly.
Your previous example would look like this (if you wanted coolIvar to not be publicaly advertised):
// in .h file
#interface MyObject : NSObject
#end
// in .m file
#interface MyObject () <-- Like a category but with no name
#property (assign) id coolIvar;
#end
#implementation
#synthesize coolIvar = _coolIvar;
#end
I use the _ivar construct to make sure that I don't access the ivar directly (by mistake) when I really intend to go through the accessors.
With the modern runtime (iPhone applications and 64-bit programs on Mac OS X v10.5 and later) the ivar declaration is no longer required. So your code is reduced to:
// in .h file
#interface MyObject : NSObject
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;
#end
Per #Monolo's answer, the _ivar is a good failsafe to make sure you don't inadvertently access the ivar directly. Remember, the #property and #synthesize is there to replace boilerplate code - without it you'd have to code getter and setter accessors.
There are a couple benefits to differentiating ivars from property accessors.
One is described by Monolo - it prevents mistakingly accessing an ivar when what you intended to access was a property.
Another is that in theory it guards against collisions - cases where you might name an ivar identically to another ivar that's beyond your implementation (ie, a superclass ivar name).
There are different thoughts on best practices, but lately I've read in several places I consider reliable that the best practice is actually to no longer to declare ivars at all in your interfaces (ivars are created implicitly via the property declaration).
Some people don't like "implicit" - but there are material benefits: Not declaring them avoids advertising ivars that aren't really public. It also goes even further in avoiding collisions - because in theory when a property is synthesized and the ivar generated, it will do so without introducing a convention that may itself collide with a private ivar naming convention (as may be the case with preceding or trailing underscore).
Preference. Some people like to prefix instance variables with a underscore (so one can easily tell if one is referencing a ivar, or a variable in a more local scope), and some don't.
I'm a bit confused; if an object is declared in the .h file it is considered automatically as "public" right? We use a #property in the .h file, however, to edit them? This is where I don't understand: we use the getter/setter for private objects, so why do we use the #property for objects declared in the .h file and thus considered as "public"?
Second thing, I found this example: I don't understand why we use a #synthesize for primaryKey in this code: http://staging.icodeblog.com/wp-content/uploads/2008/08/9-todom1.png
and why we don't use a #property for the database object?
It is not correct that if an object (ivar) is declared in a .h file, then it is public. It is only if getter/setter methods are provided, otherwise it is not.
Indeed, the #property/#synthesize directives are facilities meant to declare and define default getter/setter methods. So, instead of writing them yourself, you just use the directives.
It is also worth noting that declaring properties you get the possibility of using the dot notation to refer properties of your objects. And also that they clarify a lot, thanks to the retain/assign/copy specifiers, how memory is meant to be managed for that properties. (And, of course, #synthesize will just do that correctly for you).
About your sample, in fact, whether an ivar is associated to a property or not is a design choice. Possibly, you just reconsider the assumption that ivars declared in .h files are public by defaults, and it will become clearer. In other words: primaryKey is public, database is not.
A very nice tutorial can be found here but also do not forget Apple docs.
EDIT:
about your question from the comment section:
it is not necessary that every ivar has a property, nor that it has getter/setter in order to be used inside of that class implementation.
#interface SomeClass : NSObject {
AnotherClass* _anotherClassObj;
AThirdClass* _aThirdClassObj;
}
#property (nonatomic, retain) AnotherClass* anotherClassObj;
#end
So, here you have two ivars; only one has got a #property declaration. In your .m file you may have, e.g.
#implementation SomeClass;
#synthesize anotherClassObj = _anotherClassObj;
- (void)initWithClasses:(AnotherClass*)obj1 and:(AThirdClass*)obj2 {
.....
self.anotherClassObj = obj1;
_aThirdClassObj = obj2;
...
}
....
#end
In this code:
#synthesize will provide implementation for getter/setter for anotherClassObj so you can use syntax: self.anotherClassObj = obj1; that syntax can be used equally from inside and outside the class implementation;
when you have no getter/setter (either auto-generated or custom) you can assign directly to an ivar by using the syntax _aThirdClassObj = obj2;, with the semantics of simple pointer copy; anyway, _aThirdClassObj will not accessible from outside that class;
furthermore, #property ... anotherClassObj notwithstanding, you can still refer _anotherClassObj directly in your .m file, like in _anotherClassObj = xxx, bypassing getter/setter, if you ever need it.
One thing you should have clear is that getter/setter are not only a way to make an ivar "public". They also play an important role in managing the retain count (depending on which specifier you choose among retain/assign/copy in the property declaration). So, in self.anotherClassObj = obj1; above, obj1 is assigned to _anotherClassObj and it is also retained (and if _anotherClassObj was previously pointing to an object, that object will be sent a release). Raw ivar assignment does not provide that kind of facility.
In my opinion, the retain count management feature of properties is far more important than visibility for deciding whether I use a property or not.
Not everything in the header is public, by default ivars (items in the { }) are #protected. The purpose of the #property is data encapsulation. #synthesize or #dynamic is used for declaring the way you want to implement your property and one or the other is necessary to prevent crashes and warnings.
Resources:
Defining Classes #protected, #package, #private, #public reference
Declared Properties #property reference