I'm new to Objective-C, and I can not understand what is the difference between the declaration of variables (firstString, secondString and thirdString) in MyClass.h:
#interface MyClass {
NSString *firstString;
}
#end
in MyClass.m:
#interface MyClass() {
NSString *secondString;
}
#end
#implementation MyClass
NSString *thirdString;
#end
I guess that the first and the second case is the same thing, but in what case it is better to use?
Thanks a lot!
firstString is declared in the header, the file which is #imported by other classes. It is exposed to other classes and can therefore be accessed by subclasses and, since the symbol is available in the header file, it will be simpler for external objects to alter through key-value coding.
secondString is declared in your implementation file. The () in #interface MyClass () signifies that this is a class extension. secondString will not be exposed to external classes (though, as with everything in Objective-C, you cannot consider it to be truly private).
The first and second variables will be instance variables, whereas the third one will be a file-scope global variable. Typically you should use instance variables and avoid using global variables.
There is no functional difference between the three, it's mainly visibility control.
The first one is declared in a public header of you class, that means that you want the programmers the know about the variable. If the access to this property is restricted (e.g. #private), it should not appear in public header anymore and you should use the second or forth option.
The second is declared in the class continuation, meaning that it is needed only by the implementation.
The third one is a global variable, something you should use only in exceptional cases.
Missing another option
#implementation MyClass {
NSString *thirdString;
}
#end
(allowed by the latest Apple compilers) is the same as 2, without the need to create the class continuation.
Related
I've been writing Objective-C for a few years now, and decided to go back and learn the very basics to help me write even better code. I'm trying to learn all about instance variables, inheritance and class extensions. I've been reading up on all three, but there is one thing that boggles my mind. I have a simple app that contains 2 classes, Person, Male (inherits from Person), and of course Main (which imports the Male class, therefore being able to access the instance variables found in both Person and Male).
The code is simple, and for the sake of space I won't post all of it. Basically Main takes these variables and plays around with them. This is the part that is boggling my mind:
#interface Person : NSObject {
float heightInMeters;
int weightInKilos;
}
#property float heightInMeters;
#property int weightInKilos;
#end
When I delete the brackets and variable declarations, leaving it like this:
#interface Person : NSObject
#property float heightInMeters;
#property int weightInKilos;
#end
The code still inherits and executes just fine.
1. What is the point of even declaring them there in the first place if we can just create two properties?
2. why create two instance variables AND properties to correspond with them?
3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. like this:
#implementation Person {
float heightInMeters;
int weightInKilos;
}
What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?
When you declare a #property, the compiler will automatically synthesize the variable prefixed with an underscore, a getter method, and a setter method.
#interface MyClass ()
#property(strong, nonatomic) NSString *myString;
#end
In this example the compiler would syhtnesize the variable as _myString, the getter as
-(NSString *)myString
and the setter as
-(void)setMyString:(NSString *)string
The keywords after "#property" (strong, nonatomic) define the property's attributes. strong, the default, implies ownership, meaning that in this case MyClass instances will essentially be responsible for the retain/release of their respective myString objects. nonatomic means the variable is not guaranteed to always be a valid value in a multithreaded environment, for example if the getter is called at the same time as the setter.
Additionally, the compiler will treat dot syntax used to retrieve/set instance variables as calls to the appropriate getter/setter methods. Therefore, given an instance of MyClass
MyClass *exampleClass = [[MyClass alloc] init];
Both of the following are equivalent statements:
NSString *string1 = example.myString; // dot syntax
NSString *string1 = [example myString]; // explicit call to the getter method
For further reading, take a look at Apple's Programming with Objective-C Guide.
As for your specific questions:
1. What is the point of even declaring them there in the first place if we can just create two properties?
It's actually not a good idea to declare variables explicitly as public variables in your MyClass.h file (or in most other cases). Instead, declaring them as properties automatically creates a private variable (and accessor methods), making adhering to OOP best practices a little easier. So there is no point in declaring
// MyClass.h
#interface MyClass : NSObject {
NSString *myString // public variables not good
}
Also because of what I stated above regarding dot syntax, if you use self.myString internally in MyClass.m or instanceOfMyClass.myString externally, the public variable myString will never even be touched because the synthesized variable is named _myString.
2. Why create two instance variables AND properties to correspond with them?
See above--you don't need two instance variables, only one.
3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?
If you declare your variables privately in the #implementation part of your .m file, the compiler won't be able to help you by synthesizing the getters and setters. Even as private methods, getters and setters can help reduce complexity in your code, for example checking for the validity of variable values. (Note: you can override accessor methods.)
// MyClass.m
#interface MyClass () // private interface
#property(nonatomic, strong) NSString *myString;
#end
#implementation MyClass {
// no more need for private variables!
// compiler will synthesize NSString *_myString and accessors
}
-(void)setMyString:(NSString *)string { // overwrite setter
// no empty strings allowed in our object (for the sake of example)
NSAssert([string length] > 0, #"String must not be empty");
// assign private instance variable in setter
_myString = string;
}
#end
This way, even when you subclass MyClass, the subclass will inherit the getter and setter methods that were synthesized for us by the compiler.
The book "iOS6 by Tutorials" by Ray Wenderlich has a very nice chapter about writing more "modern" Objective-C code. In one section the books describes how to move iVars from the header of the class into the implementation file.
Since all iVars should be private this seems to be the right thing to do.
But so far I found 3 ways of doing so. Everyone is doing it differently.
1.) Put iVars under #implementantion inside a block of curly braces (This is how it is done in the book).
2.) Put iVars under #implementantion without block of curly braces
3.) Put iVars inside private Interface above the #implementantion (a class extension)
All these solutions seems to work fine and so far I haven't noticed any difference in the behavior of my application.
I guess there is no "right" way of doing it but I need to write some tutorials and I want to choose only one way for my code.
Which way should I go?
Edit: I am only talking about iVars here. Not properties. Only additional variables the object needs only for itself and that should not be exposed to the outside.
Code Samples
1)
#import "Person.h"
#implementation Person
{
int age;
NSString *name;
}
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
2)
#import "Person.h"
#implementation Person
int age;
NSString *name;
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
3)
#import "Person.h"
#interface Person()
{
int age;
NSString *name;
}
#end
#implementation Person
- (id)init
{
self = [super init];
if (self)
{
age = 40;
name = #"Holli";
}
return self;
}
#end
The ability to put instance variables in the #implementation block, or in a class extension, is a feature of the “modern Objective-C runtime”, which is used by every version of iOS, and by 64-bit Mac OS X programs.
If you want to write 32-bit Mac OS X apps, you must put your instance variables in the #interface declaration. Chances are you don't need to support a 32-bit version of your app, though. OS X has supported 64-bit apps since version 10.5 (Leopard), which was released over five years ago.
So, let's assume you are only writing apps that will use the modern runtime. Where should you put your ivars?
Option 0: In the #interface (Don't Do It)
First, let's go over why we don't want to put instance variables in an #interface declaration.
Putting instance variables in an #interface exposes details of the implementation to users of the class. This may lead those users (even yourself when using your own classes!) to rely on implementation details that they should not. (This is independent of whether we declare the ivars #private.)
Putting instance variables in an #interface makes compiling take longer, because any time we add, change, or remove an ivar declaration, we have to recompile every .m file that imports the interface.
So we don't want to put instance variables in the #interface. Where should we put them?
Option 2: In the #implementation without braces (Don't Do It)
Next, let's discuss your option 2, “Put iVars under #implementantion without block of curly braces”. This does not declare instance variables! You are talking about this:
#implementation Person
int age;
NSString *name;
...
That code defines two global variables. It does not declare any instance variables.
It's fine to define global variables in your .m file, even in your #implementation, if you need global variables - for example, because you want all of your instances to share some state, like a cache. But you can't use this option to declare ivars, because it doesn't declare ivars. (Also, global variables private to your implementation should usually be declared static to avoid polluting the global namespace and risking link-time errors.)
That leaves your options 1 and 3.
Option 1: In the #implementation with braces (Do It)
Usually we want to use option 1: put them in your main #implementation block, in braces, like this:
#implementation Person {
int age;
NSString *name;
}
We put them here because it keeps their existence private, preventing the problems I described earlier, and because there's usually no reason to put them in a class extension.
So when do we want to use your option 3, putting them in a class extension?
Option 3: In a class extension (Do It Only When Necessary)
There's almost never a reason to put them in a class extension in the same file as the class's #implementation. We might as well just put them in the #implementation in that case.
But occasionally we might write a class that's big enough that we want to divide up its source code into multiple files. We can do that using categories. For example, if we were implementing UICollectionView (a rather big class), we might decide that we want to put the code that manages the queues of reusable views (cells and supplementary views) in a separate source file. We could do that by separating out those messages into a category:
// UICollectionView.h
#interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
#property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.
#end
#interface UICollectionView (ReusableViews)
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
#end
OK, now we can implement the main UICollectionView methods in UICollectionView.m and we can implement the methods that manage reusable views in UICollectionView+ReusableViews.m, which makes our source code a little more manageable.
But our reusable view management code needs some instance variables. Those variables have to be exposed to the main class #implementation in UICollectionView.m, so the compiler will emit them in the .o file. And we also need to expose those instance variables to the code in UICollectionView+ReusableViews.m, so those methods can use the ivars.
This is where we need a class extension. We can put the reusable-view-management ivars in a class extension in a private header file:
// UICollectionView_ReusableViewsSupport.h
#interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
#end
We won't ship this header file to users of our library. We'll just import it in UICollectionView.m and in UICollectionView+ReusableViews.m, so that everything that needs to see these ivars can see them. We've also thrown in a method that we want the main init method to call to initialize the reusable-view-management code. We'll call that method from -[UICollectionView initWithFrame:collectionViewLayout:] in UICollectionView.m, and we'll implement it in UICollectionView+ReusableViews.m.
Option 2 is flat out wrong. Those are global variables, not instance variables.
Options 1 and 3 are essentially identical. It makes absolutely no difference.
The choice is whether to put instance variables in the header file or the implementation file. The advantage of using the header file is that you have a quick and easy keyboard shortcut (Command + Control + Up in Xcode) to view and edit your instance variables and interface declaration.
The disadvantage is that you expose the private details of your class in a public header. That's not desirable is some cases, particularly if you're writing code for others to use. Another potential problem is that if you're using Objective-C++, it's good to avoid putting any C++ data types in your header file.
Implementation instance variables are great option for certain situations, but for most of my code I still put the instance variables in the header simply because it's more convenient for me as a coder working in Xcode. My advice is to do whatever you feel is more convenient for you.
Largely it has to do with the visibility of the ivar to subclasses. Subclasses will not be able to access instance variables defined in the #implementation block.
For reusable code that I plan to distribute (e.g. library or framework code) where I prefer not expose instance variables for public inspection, then I'm inclined to place the ivars in the implementation block (your option 1).
You should put instance variables in a private interface above the implementation. Option 3.
The documentation to read on this is the Programming in Objective-C guide.
From the documentation:
You Can Define Instance Variables without Properties
It’s best practice to use a property on an object any time you need to keep track of a value or another object.
If you do need to define your own instance variables without declaring a property, you can add them inside braces at the top of the class interface or implementation, like this:
Public ivars should really be declared properties in the #interface (likely what you're thinking of in 1). Private ivars, if you're running the latest Xcode and using the modern runtime (64-bit OS X or iOS), can be declared in the #implementation (2), rather than in a class extension, which is likely what you're thinking of in 3.
I'm still new to Objective-C and I recently learned how to make properties, so far so good, but one thing that bothers me is that the setter and getter methods are still publicly available even after the property is made.
let's say I have the following code:
// myClass.h
#interface myClass : NSObject {
int _startPos;
}
#property (assign, readwrite, setter = setStartPos:, getter = getStartPos) int startPos;
-(void) setStartPos: (int) pos;
-(int) getStartPos;
#end
the implementation file should be rather self-explanatory, I'm not trying to do anything specific.
Now, I read somewhere, and tried it in practice that if you make a category in the implementation file, and add some methods to that, it's possible to make those methods invisible (aka private) to things outside of the myClass.m file.
"Alright" I think, and decide to try it out:
//myClass.m
#import <Foundation/Foundation.h>
#import "myClass.h"
#interface myClass (hidden)
-(void) setHiddenStartPos: (int) hPos;
-(int) getHiddenStartPos;
#end
#implementation myClass (hidden)
-(void) setHiddenStartPos: (int) hPos {
_startPos = hPos;
}
-(int) getHiddenStartPos {
return _startPos;
}
#end
#implementation myClass
-(void) setStartPos: (int) Pos {
[self setHiddenStartPos: Pos];
}
-(int) getStartPos {
return [self getHiddenStartPos]; //this is to see if I can get the value from the hidden methods through the non-hidden ones
}
#end
that's all fine, and testing it in main() I can see that the methods with "hidden" in their name are in fact inaccessible, and therefore act as if they are private.
Then I tried to add this to the header file:
#property (assign, readwrite, setter = setHiddenStartPos:, getter = getHiddenStartPos) int
to see if I could access the hidden methods through the property
but when I did that, the hidden methods became accessible in main() and the whole plan with making the methods only accessible through the property went down the drain
So I ask you, is there a way to make methods inaccessible to anything BUT the property and/or the object itself?
Edit: I realize that getters don't usually have get in the name, so please stop commenting on it?
also to emphasise what I meant:
I wanted to make properties like in c#, where the content of the setters and getters are private to the property itself
public int exampleProperty
{
set{...}
get{...}
}
it doesn't use methods as getters and setters, and therefore the code in the setters and getters are accessible to only the property, JUST like the code within a method is local to the method itself
Add a class continuation in your .m file. i.e.:
#interface myClass ()
#property (assign, readwrite, setter = setHiddenStartPos:, getter = getHiddenStartPos) int hiddenStartPos;
#end
#implimentation myClass
#synthesize hiddenStartPos = _hiddenStartPos;
...
#end
Have a look at: What is an Objective-C "class continuation"?
PS: Your getters should just be hiddenStartPos rather than getHiddenStartPos...
It seems to me that the your confusion comes from misunderstanding exactly what an #property declaration is. It is essentially a declaration that setter and getter methods exist.
So, this
#property int hiddenStartPos;
is the same as this
- (int)hiddenStartPos;
- (void)setHiddenStartPos;
So, the implementation of these two methods is the implementation of the property. By decaring the property in the .h file, you're advertising to anyone who imports the .h that the class in question implements these two methods (the getter and the setter, respectively).
I also want to reemphasize that getter methods should not be prefixed with "get" in Objective-C.
You're over-thinking what "private" means. In ObjC, "private" just means "not visible." It doesn't mean "not callable." The way you make a method private is to not put it in your .h file, which declares your public interface.
There is no way to control who passes a message. This is a key fact of ObjC and cannot (and should not) be changed. ObjC is a dynamic language. At runtime, I am free to generate selectors and call performSelector: on any object I want. Anything that stopped that would either (a) introduce significant performance penalties, or (b) break many very useful and common techniques in ObjC (probably both). ObjC is not Java or C#. It's not even C or C++. It's Smalltalk on top of C. It's a highly dynamic language and that has a lot of strengths. Unlearning other languages is the first step towards becoming a good Cocoa developer.
It would be nice to have a compiler-checked #private for methods (of which properties are just a special case), and it would especially be awesome to have a compiler-checked #protected for methods (these exist for ivars). These would make it slightly simpler to avoid some kinds of mistakes. But that's the only way you should be thinking about this. The goal is not to protect one part of the code from another part of the code. The other code is not the enemy. It's all written by people who want the program to work. The goal is to avoid mistakes. Correct naming, consistency, and the absolute elimination of warnings is how you achieve that in ObjC.
So yes, I'd love to be able to put #protected in front of my #property declarations occasionally. Today you can't, and there is no real equivalent (I sometimes use a +Protected category in a separate header, but it's generally more trouble than its worth). But that said, having it wouldn't change very much, and I only find a case where I would even use this a few times a year. I can't think of single case where #private for a method would have been really useful, though.
Example:
typedef void(^responseBlock)(NSDictionary*, NSError *);
#interface MyClass : NSObject
{
[??] responseBlock responseHandler;
}
What qualifier should I put in the [??] brackets?
I've read that blocks as properties should be setup with the copy qualifier...but in this case I don't need the block exposed as a property. I simply want it to remain an ivar but how can I specify copy? And also, without specifying anything what is the default qualifier used? Is it __strong as in the case with everything else?
I'm using ARC on ios5.
Yes, Blocks are objects in ObjC, so __strong is the appropriate qualifier. Since that's the default, you can in fact leave it off.
There's no way for you to specify that the Block be copied on assignment without a property -- that will be your responsibility (responseHandler = [someBlock copy];). You could declare a property that's only visible to this class itself (not available to other code) by putting a class extension in your .m file:
#interface MyClass ()
#property (copy) responseBlock responseHandler;
#end
This (upon being synthesized) will give you the usual accessor methods, which will take care of the copy for you when you use them.
Also be aware that it's possible (and now the recommended procedure) to declare instance variables in the #implementation block. It sounds like you want this to be a private attribute (no property access), and the ivars declared there can't be seen by any other code. (Of course you don't need to do this if you're using a property; #synthesize will create the ivar for you.)
#implementation MyClass
{
responseBlock responseHandler;
}
// Continue with implementation as usual
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
In objective C I am seeing lots of code with a underscore before variable names e.g _someVariable
why is that? also how to you write accessors i.e get and set method for such a variable.
The underscores are often used to show that the variables are instance variables. It is not really necessary, as ivars can have the same name as their properties and their accessors.
Example:
#interface MyClass : NSObject {
NSString *_myIVar; // can be omitted, see rest of text
}
// accessors, first one is getter, second one is setter
- (NSString *) myIVar; // can be omitted, see rest of text
- (void) setMyIVar: (NSString *) value; // can be omitted, see rest of text
// other methods
#property (nonatomic, copy) NSString *myIVar;
#end
Now, instead of declaring and coding the accessors myIVar and setMyIVar: yourself, you can let the compiler do that. In newer versions, you don't even have to declare myIVar in the interface. You just declare the property and let the compiler synthesize the rest for you. In the .m file, you do:
#implementation MyClass
#synthesize myIVar; // generates methods myIVar and setMyIVar: for you,
// with proper code.
// also generates the instance variable myIVar
// etc...
#end
Be sure to finalize the string:
- (void) dealloc {
[myIVar release];
[super dealloc];
}
FWIW, if you want to do more than the default implementation of the getter or setter do, you can still code one or both of them yourself, but then you'll have to take care of memory management too. In that case, the compiler will not generate that particular accessor anymore (but if only one is done manually, the other will still be generated).
You access the properties as
myString = self.myIVar;
or, from another class:
theString = otherClass.myIVar;
and
otherClass.myIVar = #"Hello, world!";
In MyClass, if you omit self., you get the bare ivar. This should generally only be used in the initializers and in dealloc.
Don't do it.
Single leading underscores are an Apple internal coding convention. They do it so that their ivar names won't collide with yours. If you want to use a prefix on your ivar names, use anything but a single underscore.
this is a naming convention normally used for c++ to define instance variable which are private
like in a class u may have
private:
int __x;
public:
int GetX()
{
return this.__x;
}
this is a naming convention, i was forced to use in c++. However my teacher never told us the name of the naming convention. But i feel this is helpfull and readable specially when u are not using java naming conventions.