Is there a difference between an "instance variable" and a "property" in Objective-c?
Asked Answered
S

6

84

Is there a difference between an "instance variable" and a "property" in Objective-c?

I'm not very sure about this. I think that an "property" is an instance variable that has accessor methods, but I might think wrong.

Scoop answered 9/5, 2009 at 16:53 Comment(0)
Z
87

A property is a more abstract concept. An instance variable is literally just a storage slot, like a slot in a struct. Normally other objects are never supposed to access them directly. A property, on the other hand, is an attribute of your object that can be accessed (it sounds vague and it's supposed to). Usually a property will return or set an instance variable, but it could use data from several or none at all. For example:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(Note: The above code is buggy in that it assumes the name already exists and has at least two components (e.g. "Bill Gates" rather than just "Gates"). I felt that fixing those assumptions would make the actual point of the code less clear, so I'm just pointing it out here so nobody innocently repeats those mistakes.)

Zito answered 9/5, 2009 at 17:29 Comment(3)
The way that I have been viewing property's is a means of providing/restricting access to the instance variables for external objects. Kind of like the public/private concept in other languages?Galibi
"Normally other objects are never supposed to access them directly" what do you mean by this? Also is your answer updated with modern objective-c?Hardness
@Honey I think he's referring to the concept of encapsulation and following best practices. Other objects shouldn't be able to directly access or modify the ivar. By controlling ivar access via properties we can intercept those calls before they potentially affect the ivar. See here for more info: en.wikipedia.org/wiki/Encapsulation_(computer_programming)Coprophilia
M
34

A property is a friendly way of implementing a getter/setter for some value, with additional useful features and syntax. A property can be backed by an instance variable, but you can also define the getter/setter to do something a bit more dynamic, e.g. you might define a lowerCase property on a string which dynamically creates the result rather than returning the value of some member variable.

Here's an example:

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

The @property line defines a property called propertyName of type NSString *. This can be get/set using the following syntax:

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

When you assign to or read from myObject.propertyName you are really calling setter/getter methods on the object.

The @synthesize line tells the compiler to generate these getter/setters for you, using the member variable with the same name of the property to store the value (or otherVarName if you use the syntax in comments).

Along with @synthesize you can still override one of the getter/setters by defining your own. The naming convention for these methods is setPropertyName: for the setter and propertyName (or getPropertyName, not standard) for the getter. The other will still be generated for you.

In your @property line you can define a number of attributes in parens for the property that can automate things like thread-safety and memory management. By default a property is atomic meaning the compiler will wrap @synthesized get/set calls with appropriate locks to prevent concurrency issues. You can specify the nonatomic attribute to disable this (for example on the iPhone you want to default most properties to nonatomic).

There are 3 attribute values that control memory management for any @synthesized setters. The first is retain which will automatically send release to old values of the property, and retain to the new values. This is very useful.

The second is copy which will make a copy of any values passed in rather than retaining them. It is good practice to use copy for NSString because a caller could pass in an NSMutableString and change it out from under you. copy will make a new copy of the input which only you have access to.

The third is assign which does a straight pointer assign without calling retain/release on the old or new object.

Lastly you can also use the readonly attribute to disable the setter for the property.

Machos answered 9/5, 2009 at 17:53 Comment(1)
Is there any benefit to declaring the instance variable and the property (e.g propertyName)? The declaration inside the interface is not needed if you declare a property for the same variable, correct? This really saves on lines of code, unless there's something I'm missing..Chaetopod
N
6

I use properties for the interface part - where the object interfaces with other objects and instance variables are stuff that you need inside your class - nobody but you is supposed to see and manipulate those.

Noddle answered 15/6, 2013 at 13:54 Comment(0)
S
3

By default, a readwrite property will be backed by an instance variable, which will again be synthesized automatically by the compiler.

An instance variable is a variable that exists and holds its value for the life of the object. The memory used for instance variables is allocated when the object is first created (through alloc), and freed when the object is deallocated.

Unless you specify otherwise, the synthesized instance variable has the same name as the property, but with an underscore prefix. For a property called firstName, for example, the synthesized instance variable will be called _firstName.

Spermophile answered 28/5, 2016 at 11:13 Comment(0)
S
2

Previously people use properties publicly and ivars for private usage, but since several years ago, you can also define properties in @implementation to use them privately. But I'd still use ivars when possible, since there are less letters to type, and it runs faster according to this article. It makes sense since properties are mean to be "heavy": they are supposed to be accessed from either generated getters/setters or the ones manually written.

However, in recent codes from Apple, ivars are not used anymore. I guess because it's more like objc rather than C/C++, plus it's easier to use properties with assign, nullable, etc.

Stasny answered 7/6, 2016 at 13:15 Comment(1)
My guess is that Apples usage of properties in @implementation wants to show similarities with Swift. Still I also prefer backing variables to not waste a virtual function call in order to lookup a simple field of my own class (and that happens when the property is accessed).Herbal
A
1

Objective-C Property vs Instance variable (iVar)

[Swift variable, property...]

Instance variable

@interface SomeClass: NSObject
NSString *someVariable;
@end

Property

@interface SomeClass: NSObject
@property (nonatomic, strong) NSString *someVariable;
@end

Property uses Instance variable inside. property = variable + bounded getter/setter. It is a method call with variable syntax and access

  • @property generates getter and setter methods(accessor methods) which uses backing ivar(aka backing field) which you can use via underscore _<var_name> (_someVariable).

  • Since it calls a method - method dispatch mechanism is used that is why KVO[About] can be applied

  • When you override accessor methods backing iVar is not generated that is why you can declare a new property explicitly or use @synthesize[About] to generate a new one or link with existing

#import "SomeClass.h"

@interface SomeClass()
@property (nonatomic, strong) NSString *someVariable;
@end

@implementation SomeClass

- (void) foo {

    //property getter method
    NSString *a1 = self.someVariable; //NSString *a1 = [self someVariable];

    //property setter method
    self.someVariable = @"set someVariable"; //[self setSomeVariable:@"set someVariable"];

    //iVar read
    NSString *a2 = _someVariable;
    //iVar write
    _someVariable = @"set iVar";

}

//if you overriding someVariable getter and setter the iVar(_someVariable) is not generated, that is why you can:

//1. create some variable explicitly
NSString *_someVariable;

//or

//2. use @synthesize 
@synthesize someVariable = _someVariable;

//overriding
- (NSString*) someVariable {
    return _someVariable;
}

- (void)setSomeVariable: (NSString*) updatedSomeVariable {
    _someVariable = updatedSomeVariable;
}

@end

[property attributes]

Ardisardisj answered 16/2, 2021 at 22:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.