Alternatives to const instance variables in Objective-C? - objective-c

Since Objective-C doesn't support const instance variables in classes what are some alternatives to ensure the value of the variable doesn't get changed? I do not want to resort to preprocessor #defines because I would prefer class variables. Also, is there a reason const instance variables aren't supported?

Objects in Objective-C are constructed differently than those in C++ or Java. All instance variables are initialized to zero by the alloc method, before the init method is called, so it would be too late by the time init is called to change a const instance variable. Obviously the compiler writers could modify the compiler to support changing a const instance variable in an init method, but they haven't done so.
Typically you just make your instance variables #private and expose them using accessor methods. If you don't want an instance variable's value to change, don't expose a setter method and don't modify the variable in your class implementation.
If you drop support for 32-bit Mac OS X, you can put your instance variables in your #implementation instead of your #interface, which completely protects them from meddling by other classes.

Related

Objective-C Property Getter/Setter crash EXC_BAD_ACCESS

I was wondering why assigning values to properties in another class causes EXC_BAD_ACCESS. I can't seem to figure out why.
1.) The value being sent into the setter is non-nil;
2.) When trying to assign the value, EXC_BAD_ACCESS happens, the variable is nil;
Using this pattern in both Cocoa and Cocoa Touch applications both causes EXC_BAD_ACCESS, so I don't think it's the platform, but I believe it's the pattern I'm using.
My questions are, is it when the variables are assigned, or is it the way I'm creating the properties?
I have created a dummy project which is seen in the pictures below.
Any help is appreciated.
EDIT: Doing some digging, I changed the name of the setter's variable (not the property name) to firstName__. Basically, the code in the setter for setFirstName:
- (void)setFirstName:(NSString *)firstName__
{
self.firstName = firstName__;
}
Doing this cleared up a little confusion by saying firstName__ (and not self.firstName) is equal to nil, even though in the AppDelegate, the value is non-nil.
Your problem is recursion. In the setter, you are calling the setter method again, and again and again.
When you declare
self.firstName = first name__;
is basically the equivalent of
[self setFirstName:first name__];
So the method is calling itself which doesn't make much sense to do.
You first need to wrap your head around properties and instance variables.
Objective C class instances often contain instance variables that hold values.
Even though it is possible to expose these variables to outside world via #public qualifier, this is not the established convention.
The convention is to have properties, which behind the scenes are a "wrapper" around private instance variable.
Since in Objective C you can only communicate with other objects via messages, to be able to access the values of instance variable you have setter and getter methods that are invoked when you send an appropriate message to the object.
Modern objective C creates instance variable for you implicitly when you declare properties. It is often said that those properties are backed by instance variables.
Normally there is no reason to explicitly implement setters and getters, as the compiler does this for you behind the scenes. (in a same manner, it also creates those instance variables for you)
But if you want to implement setters explicitly, you need to set the instance variable in the setter, not call the setter itself again (via dot notation convention) as I explained above.
Implicitly created instance variables have a naming convention with underscore as prefix. In your case it is
_firstName
When you declare a property called firstName, you also get an instance variable
_firstName
You setter should look like this
-(void)setFirstName:(NSString *)firstName
{
_firstName = firstName;
}
And getter
-(NSstring *)getFirstName
{
return _firstName;
}

Difference between a property and a global variable [objective c]

I'm wondering what the difference between a class's public global variable and a class's property is (Objective-C primarily iOS programming). Only thing I notice is that you have to use pointer notation -> to access a class's global variable rather than a dot.
I've read that changing code from using globals to using properties can be a program breaking change. Is that true and if so, why?
Thanks!
Edit:
Block.h
Public Global Variable (I think?) [Edit: I now understand this is an Instance Variable, thanks]
#interface Block : GameObject {
#public
int type;
SKEmitterNode *particles;}
Property
#property (nonatomic) CGFloat x;
No, this is not a "global variable".
It is called an instance variable.
A property often (but not necessarily) has an associated instance variable, but the modern compilers hide that from you.
The big difference between using an instance variable is, that a property is always accessed through its accessors (in your case setX:(CGFLoat)x?and -(CGFloat)x`.
If you wanted, you could overwrite these accessors and do special handling, say, whenever the variable is accessed.
It is always possible to bypass the accessors by using the instance variable directly. In a case of an auto-synthesized iVar, this would be _x.
Note that the -> is not necessary in either case
Even a class property is backed by a class variable even though it is not global.
But with a property one has additional gatekeepers guarding access to the variable:
You can make the property readonly.
Finetune memory semantics (copy, assign, etc).
By using KVO it is easy to let changes propagate automatically.

When to use instance variables and when to use properties

When using Objective-C properties can you stop creating instance variables altogether or do explicit instance variables (not the ones synthesized by the properties) still serve a purpose where properties would be inappropriate?
can you stop creating instance variables altogether
No, you can't (in a sense). What you can do is stop declaring them if you have properties. If you synthesize a property and you haven't declared the instvar, it will get declared for you, so you are creating an instance variable, just not explicitly.
do they still serve a purpose where properties would be inappropriate?
It used to be the advice to create properties for everything because having synthesized properties does almost all of the retains and releases for you. However, with ARC that reason for using properties to wrap the memory management has gone away. The advice now (for ARC) is, I believe, use properties to declare your external interface, but use direct instance variables where the variable is part of the object's internal state.
That's a good reason to adopt ARC: properties revert to their true purpose only of being part of the class's API and it's no longer necessary to use them as a hacky way to hide memory management work.
Edit
One more thing: you can now declare instance variables in the #implementation so there is now no need to leak any implementation details in the #interface. i.e.
#implementation MyClass
{
NSString* myString;
}
// method definitions
#end
And I'm pretty sure it works in categories too. - see comment below
I recommend declaring everything as properties and avoiding manual ivars altogether. There is no real upside to manually creating ivars. Declare public properties in your header #interface, declare private properties in a private class extension in your .m file.
To some of JeremyP's points, internal use of accessors still has significant value under ARC, even though memory management is no longer a significant concern. It ensures that KVO works properly, subclasses better, supports custom setters (particularly for things like NSTimer), supports custom getters (such as for lazy instantiation), etc. It is exceedingly error-prone to have a mix of accessors and ivars. It's far too easy to forget which you need to access in which way. Consistency is the hallmark of good ObjC.
If you absolutely must declare an ivar for some reason, then you should do it in the #implementation block as JeremyP notes.
UPDATE (Oct-2013):
Apple's guidance (From Programming with Objective-C: Encapsulating Data):
Most Properties Are Backed by Instance Variables
In general, you should use accessor methods or dot syntax for property access even if you’re accessing an object’s properties from within its own implementation, in which case you should use self:
...
The exception to this rule is when writing initialization, deallocation or custom accessor methods, as described later in this section.
This question was addressed before here
When you use synthesize the instance variables are handled and instantiated for you. If you're using Lion with the new version of XCode also take a look at the various properties in ARC in Transitioning to ARC
you can always access properties from outside. So if you want a variable only to be read from inside a class you still have to declare a iVar. Also accessing a public ivar with object->ivar is slightly faster than using a method-call.

Application-wide variable access: static like Java?

I have an instance variable in my view controller that I would like to share with the whole program. I'm not quite sure how to do this. Can I just declare it as a static instance variable and then access it through properties like ViewControllerClass.instancevariable?
Thanks!
In reply to your comment attached to the question:
If you have an instance variable in Object X, any other object that has a reference to X can access that variable through the usual means:
[objectX myClassAInstanceVariable];
// Or, if declared with #property
objectX.myClassAInstanceVariable;
If the other object doesn't have a reference to X, then it can't access the variable, no matter the state or kind of the variable. In this case, you may want to rethink your design, or see my last paragraph below about the app delegate.
The concept of "static" is different in Objective-C than what you may be expecting (it sounds like you're coming from experience with Java).
Objective-C doesn't really have a concept of "class variables", although it is fairly easy to simulate such a thing; this is described in the question that mathk linked to: Objective-C Static Class Level variables. You declare a variable in the class's header file which is static, so that it is inaccessible outside that file, and create accessor class methods for it.
Any object that has a reference to your view controller can send messages to it. Note that in Objective-C, member variables are "protected" by default, meaning that only an instance of a class or subclasses, not other objects, can access those variables. Other objects must go through setter and getter methods.
Just as another option, because the background of your question is not clear, if you have some kind of a "global variable" which isn't really specific to your view controller, a better place to put it may be the application delegate*. Any object can get a reference to the delegate at any time:
[NSApp delegate];
NSApp is a global reference to the NSApplication object which is at the core of your program.
*Although it's certainly possible to overdo this.

share a property among different instance of the same class

Is it possible to share one parameter of a class among all the instances of this class, in objective-c?:
#interface Class1 : NSObject {
NSString* shared; /** shared among instance (this is not, but defined somehow) **/
NSString* non_shared; /** other parameters non shared **/
}
In the program then, each instance of Class1 has its own non_shared variables (as usual), but all access the same shared one (when one instance changes it all can see it).
One possibility is to hide the variable as a property and use a singleton in the setter/getter functions, but I don't know if there is a simple way.
Thanks,
Edu
Class variables (called static in many other OOP languages) are actually a bit of a pain in Objective-C. You have to declare a static global variable in the class' module (.m) file and reference that variable. You should add class-level getter/setters to encapsulate access to the static global variable. Your getter can alloc/init an object and put it in the variable if it is uninitialized before returning it.
If the static variable holds an instance (e.g. an NSString instance in your example), you need to make sure it doesn't get alloc/initialized more than once. Take a look at dispatch_once if you're on OS X 10.6 or greater to guarantee single initialization.