This question already has answers here:
Must every ivar be a property?
(4 answers)
Closed 9 years ago.
Lately, it seems that explicitly declared instance variables in Objective-C are considered a thing to avoid, with the preference being to use "private" properties, i.e., properties declared in a class extension in the .m file.
The last example of this is the WWDC '12 presentation on advances in Objective-C.
What I haven't been able to find is a rationale for this preference, and I have searched a lot. It obviously provides a sort of solution to the fragile base class problem, but that was already solved with Objective-C 2.
Is there some crucial piece of documentation that I have missed, or is there a simple explanation that a kind soul could provide here?
You mean this?
#interface Foo : NSObject {
float bar;
id baz;
}
If those instance variables are not a part of the public interface, you will do better to move them into the implementation file, either as declared properties in a class extension or to the #implementation block:
#interface Foo ()
#property(assign) float bar;
#property(strong) id baz;
#end
…or:
#implementation Foo {
float bar;
id baz;
}
This way the public interface declared in the header stays simple and changes in the implementation won’t force a recompilation of all the source files that import the header.
Related
This question already has answers here:
Varieties of #interface declarations, some with parentheses
(3 answers)
Closed 8 years ago.
I'm looking at a .h file for an Objective-C class and I see multiple interface declarations in it and I am unsure as to what the differences are and what they mean.
First I see
#interface TAModel : NSObject
Which I recognize. TAModel is the class and NSObject is it's super class. What I'm confused about is further down I see another interface declaration:
#interface TAModel (Protected)
Also inside another .m file (unrelated to the first two) I have seen:
#interface TAWorker (Private)
I was wondering what the second two mean, what they are doing. As far as I know with objective-c there is no true protected visibility between classes.
It's creating a category class in which they're putting their protected/private members. The usual idiom is just to create a class extension (so you'll often see #interface Foo (); the difference here is that you can also declare more fields, not just properties and methods) in the .m file.
Neither way of doing this truly protected or private as you can still technically get at the things declared there by casting to id first or through one of the performSelector: methods. But it's pseudo-private because you don't publish the interface publicly if it's not in the .h file.
This question already has an answer here:
Can category methods be overridden? IOS
(1 answer)
Closed 8 years ago.
I have a class structure of the type UIViewControllerSubclass : UIViewController, where the only function of UIViewControllerSubclass is to #import UIViewController+Category.h. The reason I added methods in a category is so that I can also make UITableViewControllerSubclass : UITableViewController, which will #import UIViewController+Category.h as well. As we all know, don't repeat yourself.
Now assume that UIViewController+Category.h has the structure:
#interface UIViewController(Category)
- (void) method1;
- (void) method2;
#end
How safe is it to create UIViewControllerSubclassSubclass : UIViewControllerSubclass, which will override method1? I assume this will work because of Objective-C's message passing, but for some reason my intuition is telling me that I'm doing it wrong.
Everything should work fine since the category is applied to UIViewController, so all instances of UIViewController, including subclasses, will have access to the methods. There's nothing unsafe about it; that's how categories are intended to be applied.
This question already has answers here:
How to make a real private instance variable?
(7 answers)
Closed 8 years ago.
How exactly should attributes be declared if they are needed to be private and the language supports automatic getter/setter method creation?
Is the only way to override the automatically created getter or setter as needed?
In the top of the .m (implementation) file:
// Private category on your class, declared at top of implementation file.
#interface MyClass ()
#property (nonatomic, copy) NSString * privateString;
#end
#implementation
...
#end
These "private properties" are visible only within your implementation.
Please note that ObjC has no facility for runtime access restriction. Other objects can still call your private getters and setters if they want to (although this will generate compiler warnings).
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 always thought that one cannot declare an object property in a category.
Until my partner did it in our app's code, and it seemed to work.
I went on a SO and Google binge to try to explain to him that no, Objective-C categories can only be used to add methods, not properties. I found questions such as:
Setting New Property In Category Interface Implementation (look at the accepted answer)
Can I add a property for a method not in my category?
But then I found this link on Apple's site that contains the following about the #property declaration:
A property declaration begins with the
keyword #property. #property can
appear anywhere in the method
declaration list found in the
#interface of a class. #property can
also appear in the declaration of a
protocol or category. (emphasis added)
I know that this doesn't work:
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
But this compiles:
#interface MyClass ()
#property NSInteger foobar;
- (void) someCategorizedMethod;
#end
My question is (a) what's the best practice here? and (b) is this something that is new to Objective-C 2.0, and instead of using a "real" iVar, it simply uses associative storage behind the scenes to make this work?
You have always been able to declare an #property in a category. What you couldn't do -- and still can't -- is declare storage for the property in the category, neither as an instance variable nor via `#synthesize.
However....
#interface MyClass () is not a category. It is a class extension and has a distinctly more specific role than a category.
Namely, a class extension can be used to extend a class's #interface, and this includes #properties that can be #synthesized (including synthesizing storage in the modern runtime).
Foo.h:
#interface Foo
#end
Foo.m:
#interface Foo()
#property int x;
#end
#implementation Foo
#synthesize x; // synthesizes methods & storage
#end
it simply uses associative storage
behind the scenes to make this work?
Nope -- it is a real instance variable. The modern runtime fixes the fragile base class problem.
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
The above doesn't work (as expected) because foobar is, effectively, a global variable.
If you change it to:
#interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
#end
Then it'll work with the latest release of the llvm compiler (with the right flags, as #Joshua indicated in a comment).
Generally speaking, properties are nothing different from other methods. As long as the ivar used is available in the ordinary class, there is no problem at all. It's just syntactic sugar.
Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.
The main point here is that declaration of the ivar is independent from the property.
Assotiative storage is the solution.
Have a look at this post.