I am reading "Effective Objective-C 2.0: 52 Specific Ways to Improve Your iOS and OS X Programs". In "Item 6", the author says that using a pointer on a public ivar is a bad idea, because compiled code will have hardcoded pointer offset, and when new ivar will be added to class, then previously used pointers to some ivars can now point on other variable.
#interface Foo
{
#public
NSString * string;
NSArray * arr;
}
#end
#implementation
...
#end
int main()
{
#autoreleasepool
{
Foo *f=[Foo new];
f->string; //Is it bad idea?
}
return 0;
}
But, aren't ivars and properties dynamic (offset is not known at compile-time)? As Cocoa With Love says:
"All ivars are dynamic in the modern runtime: Since this procedure is followed for all ivars, that means that all ivars in the modern Objective-C runtime are dynamic in that their absolute offsets are never known at compile-time."
If that's true, then why is using a pointer on an ivar bad? Please provide as much low-level detail as possible.
If that's true, then why is using a pointer on an ivar bad? Please
provide as much low-level detail as possible.
Because it breaks encapsulation.
What if class Foo has some custom logic that should be fired when string changes? Or it has to do a calculation? Or Foo wants to make the storage of string unique-ified? Or something else wants to observe changes to said property? Or Foo wants to change the storage semantics later? Or someone wants to subclass Foo and change the behavior there?
Not a problem: "All instance variables in 64-bit Objective-C are non-fragile. That is, existing compiled code that uses a class's ivars will not break when the class or a superclass changes its own ivar layout. In particular, framework classes may add new ivars without breaking subclasses compiled against a previous version of the framework." (https://developer.apple.com/LIBRARY/mac/releasenotes/Cocoa/RN-ObjectiveC/index.html)
This also holds for the 32 bit modern runtime, of course.
Apart from the implementation technicalities, it's an exceptionally bad design though, as bbum notes.
Related
So ... I'm still fairly new to Objective C ... taking some iTunes U corses ... doing some exercises and all ...
But when you uses to do #synthesize myProperty = _myIvarPropertyNameToUse; ... iOS 5 would create an ivar that would "back" the property.
What exactly is going on here as far as where things sit in memory ...
(1) Is the ivar a true variable? ... or is it a pointer to the location of the property in the object?
(2) The property is on the heap, (being part of the object), right? Is the ivar on the heap as well?
I think I may be losing the big picture ... what's the point of having a property backed by an ivar?
thanks,
An Objective-C object is just a C struct that is allocated on the heap (well, more or less). When you declare an instance variable (ivar), it is defined as an offset into that struct. So if you manually declared some ivars like this (don't do it this way anymore, but it illustrates the point):
#interface Foo : NSObject {
NSString *ivar1;
NSString *ivar2;
}
Then when you +alloc a new instance (call it foo), the struct will be some header followed by the ivars of NSObject followed by memory for ivar1 followed by memory for ivar2. ivar1 will be the foo point plus some offset. (This isn't exactly true anymore, but stay with me; it's simpler to understand the old implementation.)
Since foo is a pointer to a struct, you can actually refer directly to this offset pointer as foo->ivar1. It really is a struct. Never do this, but it is legal syntax.
Inside of the #implementation block, ivar1 is automatically translated to self->ivar1. Don't worry too much about how self is implemented, but trust that it's a pointer to your struct. Again, never use this -> syntax. It's an underlying implementation detail (and isn't always possible anymore; see below).
OK, so that's what an ivar is. In the old days (ObjC 1.0), that's actually all we had. You declared your ivars, and then you hand-created accessor methods that would set and return their values.
Then ObjC2 comes along, which in some cases also gave us something called the non-fragile ABI. That changes the underlying implementation of ivars somewhat, so you can't always actually use -> anymore. But you shouldn't have been using it anyway. Even so, it's simpler to pretend things are the old way. More to the point, ObjC2 added this new thing called "properties." A property is just a promise to implement certain methods. So when you say:
#property (nonatomic, readwrite, strong) NSString *property;
this is almost identical to saying the following:
- (NSString *)property;
- (void)setProperty:(NSString *)aProperty;
(The difference is very seldom important.) Note that this doesn't provide an implementation. It doesn't create ivars. It just declares some methods.
Now in ObjC1, we wrote the same accessor code over and over and over again. You had 20 writable ivars, you wrote 40 accessor methods. And they were almost identical. Lots of opportunities to mess up. And a lot of tedium. Thank goodness for Accessorizer.
With ObjC2, the compiler would give you the most common implementation for free if you added #synthesize. It would automatically make an ivar with the same name as the property, and write a getter and (if needed) setter to read and write that ivar. Passing =_property just changes the name of the ivar used. We call this the "backing ivar."
Now, in the latest version of the compiler, you don't even need #synthesize. This pattern is so insanely common, and has been for decades, that it is now the default unless you tell the compiler not to do it. And it automatically synthesizes an ivar with a leading underscore (which is best practice).
The one other piece of information you should know is that you should always use the accessor to access the ivar, even inside of the object. The only exceptions are in the init and dealloc methods. There you should directly access the ivar (using the leading underscore).
Just to be clear, when you do #synthesize myProperty = _myIvarPropertyNameToUse;, your only changing the name of the backing ivar. The line #synthesize myProperty; would also create a backing ivar, but it would be called myProperty, instead of _myIvarPropertyNameToUse...
The backing ivar is part of the object, so yes it's on the heap. It can be used as a true variable, meaning you can get and set it in the object code.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Setters and Getters (Noobie) - iPhone SDK
I am a beginner here. I have just started learning iOS for the last two months and I do not have any programming background. (Little bit of Java though). Can anyone please explain what is getter and setter in Objective C? What is the use of them? Why do we use #property and #synthesize?
Getter is a method which gets called every time you access (read value from) a property (declared with #property). Whatever that method returns is considered that property's value:
#property int someNumber;
...
- (int)someNumber {
return 42;
}
...
NSLog("value = %d", anObject.someNumber); // prints "value = 42"
Setter is a method which gets called every time property value is changed.
- (void)setSomeNumber: (int)newValue { // By naming convention, setter for `someValue` should
// be called `setSomeValue`. This is important!
NSLog("someValue has been assigned a new value: %d", newValue);
}
...
anObject.someNumber = 19; // prints "someValue has been assigned a new value: 19"
Usually it doesn't make much sense to just return the same value from getter and print new value in setter. To actually store something you have to declare an instance variable (ivar) in your class:
#interface SomeClass : NSObject {
int _someNumber;
}
and make accessors (the collective name for getters and setters) to store/retrieve it's value:
- (int)someNumber {
return _someNumber;
}
- (void)setSomeNumber:(int)newValue {
_someNumber = newValue;
}
...
SomeClass *anObject = [[SomeClass alloc]init];
anObject.someNumber = 15;
NSLog(#"It's %d", anObject.someNumber); // prints "It's 15"
Okay, now that property behaves just like the usual variable. What's the point in writing all that code?
First, from now on you can add some extra code to the accessors, which will get executed each time the property is accessed or changed. There are multiple reasons for doing that, for example I may want to do some kind of hidden calculations, or updating my object's state, caching stuff etc.
Second, there are cool mechanisms called Key-Value Coding (KVC) and Key-Value Observing (KVO) in Cocoa. They depend on properties. You can read about them in the Developer Library: KVC Programming Guide and KVO Programming Guide. Those are advanced topics though.
Last, in Objective C there is no static allocation for objects. All the objects are dynamically allocated (reason). If you want to keep your object pointers in instance variables (as opposed to properties) you will have to do all the memory management manually every time you assign new value to your ivar (not true when Automatic Reference Counting is on). Using properties you could put some memory management code in the accessors and make your life easier.
I don't believe this explanation will make much sense to someone who is not familiar with Objective C memory management, so, either read some real docs/tutorials on it, or just use properties (instead of instance variables) until you learn all the details one way or another. Personally, I don't like the second option, but it's up to you.
You can use #synthesize to make the compiler generate basic accessors and underlying instance variables for you automatically. Instead of the code above (-(int)someNumber and -(void)setSomeNumber:) you could just write
#synthesize someNumber = _someNumber; // = _someNumbers tells compiler
// to name the instance variable `_someNumber`.
// You could replace it with = `_somethingElse`, of
// course, but that's an ill idea.
This single line generates int _someNumber variable, someNumber getter and setSomeNumber setter for you. If you want the accessors to do anything more complex than just store/retrieve the value from some instance variable, you will have to write them yourself.
Hope all this makes any sense.
"Getters" and "setters" are used to control changes to a variable (field).
A "setter", is most often used in object-oriented programming, in keeping with the principle of encapsulation. According to this principle, member variables of a class are made private to hide and protect them from other code, and can only be modified by a public member function, which takes the desired new value as a parameter, optionally validates it, and modifies the private member variable.
Often a "setter" is accompanied by a "getter" (also known as an accessor), which returns the value of the private member variable.
Getter/Setter methods may also be used in non-object-oriented environments. In this case, a reference to the variable to be modified is passed to the method, along with the new value. In this scenario, the compiler cannot restrict code from bypassing the getter/setter methods and changing the variable directly. The onus falls to the developers to ensure the variable is only modified through the these methods and not modified directly.
In programming languages that support them, properties offer a convenient alternative without giving up the utility of encapsulation.
Property "getters" and "setters" in most any object-oriented language provide an "external" or user interface around private members of instances of your classes. Some OO critics will refer to them as "syntactic sugar," but what it boils down to is that consumers of your classes will use these interfaces that you control programmatically rather than accessing the actual private member(s) themselves. This way, you can (for example) protect a private variable from receiving an invalid or out-of-range value, or make a property read-only by providing only a getter but no setter. Even more interesting is the idea that getters and setters may wrap properties that aren't natively retained in your class, but might (for example) be computed based on other instance members.
Getters and setters surely aren't unique to Objective-C; if you continue programming in other OO languages, you'll find flavors of them in C#, Java, and others.
Good luck.
I'm having a hard time understanding why I need to declare Instance Variables. Let me explain what I mean..
for example..
#interface LearningViewController : UIViewController {
UILabel *myText; // <--- Instance Variables
}
#property (nonatomic,retain) IBOutlet UILabel *myText;
-(IBAction)method:(id)sender;
#end
this can also be done as
#interface LearningViewController : UIViewController {
//instance variables go here, but are not declared, I just leave this field blank
}
#property (nonatomic,retain) IBOutlet UILabel *myText;
-(IBAction)method:(id)sender;
#end
as you can see.. in the latter example I ONLY built the setter / getter for the UILabel *myText
but in the former I declared the Instance Variables too.
Both end up working in the end
#implementation LearningViewController
#synthesize myText;
-(IBAction)method:(id)sender {
[myText setText:#"hey"];
//or
NSString *myObject = [[NSString alloc]initWithString:#"hey"];
[myText setText:myObject];
}
now both things produce the same result. So my question is, why? and what are the benefits of doing them either way?
And why would I build and object
NSString *myObject = [[NSString alloc]initWithString:#"hey"];
myText.text = myObject;
when I can just do
[myText setText:#"hey"];
thanks in advance.
Also, there are times when you want to use a protected or private iVar within a class and not make a property out of it. (for example, when you don't want to allow access of an iVar to anything but an instance of this class (private) or its descendants (protected). Properties declared in the header are available to any object that can "see" the target object. Automatically declaring ivars in the header as properties (with or without the declaration inside the curly braces) might be bad from the standpoint of information hiding.
You can also add an implementation section to your .m file: any properties you declare there will be private to the class. The benefit (obviously) is both in achieving information hiding where needed, and the ability to use the dot notation.
Originally Objective-C did not have properties and # synthesize did not exist. You had to declare your iVar (instance Variable) and write your own setters and getters.
When the language and runtime were revised to include properties and #synthesize, things were nicer. You no longer had to write your setters and getters. However you still had to declare your iVar.
Later still, the language and runtime evolved more and today, you don't even have to declare your iVar. (Although I tend to write #synthesize example = _example; so I can control what the generated iVar is named.)
This is a new feature and is only supported by relatively recent versions of the runtime. iOS versions less that 4.x are not supported, as are older versions of OSX.
If you are building software for today and the future, Go ahead and leave them out, If yot need legacy support, leave them in.
On the second part of the question, you are simply using the dot notation. You can set your myText.text equal to #"hey", the same way you are doing it in the second example.
[myText setText:#"hey"];
is synonymous to
myText.text = #"hey";
You don't need to declare an NSString to hold your value ahead of time.
You can leave iVars out, however I do not agree leaving out the iVars. The .h file in OOP is typically a header file that displays all variables and methods. It declares them. Assuming in the future you want to see what this class does, you just refer to the .h file. Or assuming someone else needs to look at that class, or use that class with his code to communicate with it. It makes it easier to look at the variables, see what is declared and what is not. That is, if you want to be programming professionally.
Now it really depends on what you want to do. The reason you would create an object is that so you are able to release it at a later time. So you continue to use it, and when you are done you just finish using it. Now creating instance variables for the whole class when they are just used in one method is not a good design decision. It is poor in a sense that the whole class is storing the variable, when in fact it is only used in one method. In this case, you should only create that object in that very method, and release it as soon as you're done with it.
Now sometimes doing
[myText setText#"hello"];
works. It really depends on your code. I guess the only way to really know the difference in situations is practice. Sometimes you need to set the label into another object, thus creating an object. Otherwise, it gets autoreleased etc...
Anyway, basically, use instance variables only for variables that are going to be used globally. And UI elements of course (since they are used by the whole class and interface builder).
Hope this helps.
As your code demonstrates, you don't technically need to declare instance variables, most of the time.
One critical exception to this is when you are compiling for the old (< 4.0) iOS runtime, as well as possibly the 32-bit Mac OS X runtime using GCC, which does not support the synthesis of instance variables.
Additionally, if you want to reserve space for later addition of instance variables (can be relevant if you are producing a framework and expect to extend a class at a later point), you'll need to explicitly declare the instance variables.
Edit: Long story short: Legacy, portability and extensibility concerns proscribe explicit ivars. For applications targeting 10.6, and especially 10.7, there is little or no need to declare them.
The documentation says:
While not strictly a part of the
language, the isa pointer is required
for an object to work with the
Objective-C runtime system. An object
needs to be “equivalent” to a struct
objc_object (defined in objc/objc.h)
in whatever fields the structure
defines. However, you rarely, if ever,
need to create your own root object,
and objects that inherit from NSObject
or NSProxy automatically have the isa
variable.
While that sounds nice, I wonder how an root object would be created in Objective-C anyways?
This is for learning purposes. I just want to know this. I'd really like to see it.
It's actually a "trap" some people migrating from C# or Java style languages fall into. You simply don't specify a superclass when declaring your class i.e.
#interface MyNewRoot {
Class isa;
}
#end
vs
#interface MyObject : NSObject {
}
#end
In Java or C# these would be equivalent (in the first case the compiler would assume System.Object or java.lang.Object was the superclass), but in Objective-C no such default will be assumed, and hence a new root is created.
However you're now responsible for a number of features for your class that you typically take for granted (even simple things like memory management for allocating or destorying new instances etc). This is what the comment you quoted hints at when it talks about struct objc_object and the isa instance variable etc.
I have several years of experience in Obj-c and Cocoa, but am just now getting back into it and the advances of Obj-C 2.0 etc.
I'm trying to get my head around the modern runtime and declaring properties, etc. One thing that confuses me a bit is the ability in the modern runtime to have the iVars created implicitly. And of course this implies that in your code you should always be using self.property to access the value.
However, in init* and dealloc(assuming you're not using GC) methods we should be using the iVar directly (in the current runtime).
So questions are:
Should we use property accessors in init* and dealloc with Modern Runtime?
If so, why is this different? Is it just because the compiler can't see the iVar?
If I need to override an accessor, can I still access that iVar that will be defined at runtime or do I have to define an actual iVar that the runtime will then use?
Again, if I can access the synthesized iVar, why can't I continue to do this for the init* and dealloc methods?
I read the docs several times, but they seemed a bit vague about all of this and I want to be sure that I understand it well in order to decide how I want to continue coding.
Hope that my questions are clear.
Quick summary of testing:
If you don't declare the ivar in legacy, compiler is completely unhappy
If you use #ifndef __OBJC2__ around ivar in legacy compiler is happy and you can use both ivar directly and as property
In modern runtime, you can leave the ivar undefined and access as property
In modern runtime, trying to access ivar directly without declaration gives error during compile
#private declaration of ivar, of course, allows direct access to ivar, in both legacy and modern
Doesn't really give a clean way to go forward right now does it?
In the current (OS X 10.5/GCC 4.0.1) compiler, you cannot directly access the runtime-synthesized ivars. Greg Parker, one of the OS X runtime engineers put it this way on the cocoa-dev list (March 12, 2009):
You can't in the current compiler. A
future compiler should fix that. Use
explicit #private ivars in the
meantime. An #private ivar should not
be considered part of the contract -
that's what #private means, enforced
by compiler warnings and linker
errors.
And why isn't there a way to
explicitly declare instance variables
in the .m file for the new runtime?
Three reasons: (1) there are some
non-trivial design details to work
out, (2) compiler-engineer-hours are
limited, and (3) #private ivars are
generally good enough.
So, for now you must use dot-notation to access properties, even in init and dealloc. This goes against the best practice of using ivars directly in these cases, but there's no way around it. I find that the ease of using runtime-synthesized ivars (and the performance benefits) outweigh this in most cases. Where you do need to access the ivar directly, you can use a #private ivar as Greg Parker suggests (there's nothing that prevents you from mixing explicitly declared and runtime-synthesized ivars).
Update With OS X 10.6, the 64-bit runtime does allow direct access to the synthesized ivars via self->ivar.
Since instance variables themselves can only be synthesized in the modern runtime (and must be declared in the #interface under 32-bit or pre-Leopard), it's safest / most portable to also declare the ivar
Should we use property accessors in init* and dealloc with Modern Runtime?
My rule of thumb is "possibly" for -init*, and "usually not" for -dealloc.
When initializing an object, you want to make sure to properly copy/retain values for ivars. Unless the property's setter has some side effect that makes it inappropriate for initialization, definitely reuse the abstraction the property provides.
When deallocating an object, you want to release any ivar objects, but not store new ones. An easy way to do this is to set the property to nil (myObject.myIvar = nil), which basically calls [myObject setMyIvar:nil]. Since messages to nil are ignored, there is no danger in this. However, it's overkill when [myIvar release]; is usually all you need. In general, don't use the property (or directly, the setter) in situations where deallocation should behave differently than setting the variable.
I can understand eJames' argument against using property accessors in init/dealloc at all, but the flipside is that if you change the property behavior (for example, change from retain to copy, or just assign without retaining) and don't use it in init, or vice versa, the behavior can get out of sync too. If initializing and modifying an ivar should act the same, use the property accessor for both.
If so, why is this different? Is it just because the compiler can't see the ivar?
The modern runtime deals with class size and layout more intelligently, which is why you can change the layout of ivars without having to recompile subclasses. It is also able to infer the name and type of the ivar you want from the name and type of the corresponding property. The Objective-C 2.0 Runtime Programming Guide has more info, but again, I don't know how deeply the details explained there.
If I need to override an accessor, can I still access that iVar that will be defined at runtime or do I have to define an actual iVar that the runtime will then use?
I haven't tested this, but I believe you're allowed to access the named ivar in code, since it actually does have to be created. I'm not sure whether the compiler will complain, but I would guess that since it will let you synthesize the ivar without complaining, it is also smart enough to know about the synthesized ivar and let you refer to it by name.
Again, if I can access the synthesized iVar, why can't I continue to do this for the init* and dealloc methods?
You should be able to access the property and/or ivar anytime after the instance has been allocated.
There is another SO question with similar information, but it isn't quite a duplicate.
The bottom line, from the Objective-C 2.0 documentation, and quoted from Mark Bessey's answer is as follows:
There are differences in the behavior that depend on the runtime (see also “Runtime Differences”):
For the legacy runtimes, instance variables must already be declared in the #interface block. If an instance variable of the same name and compatible type as the property exists, it is used—otherwise, you get a compiler error.
For the modern runtimes, instance variables are synthesized as needed. If an instance variable of the same name already exists, it is used.
My understanding is as follows:
You should not use property accessors in init* and dealloc methods, for the same reasons that you should not use them in the legacy runtime: It leaves you open to potential errors if you later override the property methods, and end up doing something that shouldn't be done in init* or dealloc.
You should be able to both synthesize the ivar and override the property methods as follows:
#interface SomeClass
{
}
#property (assign) int someProperty;
#end
#implementation SomeClass
#synthesize someProperty; // this will synthesize the ivar
- (int)someProperty { NSLog(#"getter"); return someProperty; }
- (void)setSomeProperty:(int)newValue
{
NSLog(#"setter");
someProperty = newValue;
}
#end
Which leads me to think that you would be able to access the synthesized ivar in your init* and dealloc methods as well. The only gotcha I could think of is that the #synthesize line may have to come before the definitions of your init* and dealloc methods in the source file.
In the end, since having the ivars declared in the interface still works, that is still your safest bet.
I am running into the same problem. The way I am working around not being able to access the synthesized instance variables is the following:
public header
#interface MyObject:NSObject {
}
#property (retain) id instanceVar;
#property (retain) id customizedVar;
#end
private header / implementation
#interface MyObject()
#property (retain) id storedCustomizedVar;
#end
#implementation MyObject
#synthesize instanceVar, storedCustomizedVar;
#dynamic customizedVar;
- customizedVar {
if(!self.storedCustomizedVar) {
id newCustomizedVar;
//... do something
self.storedCustomizedVar= newCustomizedVar;
}
return self.storedCustomizedVar;
}
- (void) setCustomizedVar:aVar {
self.storedCustomizedVar=aVar;
}
#end
It's not that elegant, but at least it keeps my public header file clean.
If you use KVO you need to define customizedVar as dependent key of storedCustomizedVar.
I'm relatively new to Obj-C (but not to programming) and have also been confused by this topic.
The aspect that worries me is that it seems to be relatively easy to inadvertently use the iVar instead of the property. For example writing:
myProp = someObject;
instead of
self.myProp = someObject;
Admittedly this is "user" error, but it's still seems quite easy to do accidentally in some code, and for a retained or atomic property it could presumably lead to problems.
Ideally I'd prefer to be able to get the runtime to apply some pattern to the property name when generating any iVar. E.g. always prefix them with "_".
In practice at the moment I'm doing this manually - explicitly declaring my ivars, and deliberately giving them different names from the properties. I use an old-style 'm' prefix, so if my property is "myProp", my iVar will be "mMyProp". Then I use #synthesize myProp = mMyProp to associate the two.
This is a bit clumsy I admit, and a bit of extra typing, but it seems worth it to me to be able to disambiguate a little bit more clearly in the code. Of course I can still get it wrong and type mMyProp = someObject, but I'm hoping that the 'm' prefix will alert me to my error.
It would feel much nicer if I could just declare the property and let the compiler/runtime do the rest, but when I have lots of code my gut instinct tells me that I'll make mistakes that way if I still have to follow manual rules for init/dealloc.
Of course there are also plenty of other things I can also do wrong...