Effective Objective-C 2.0:Item 7: Access Instance Variables

原创 2013年12月03日 00:14:30

initializer: set 时候直接访问ivar;get时候看具体;

一般情况下,set用accessors; get用ivar快 

Item 7: Access Instance Variables Primarily Directly When Accessing Them Internally

Properties should always be used to access instance variables of an object externally, but how you access instance variables internally is a hotly debated topic within the Objective-C community. Some suggest always using a property to access instance variables, some suggest always accessing the instance variable directly, and some suggest a mixture of the two. I strongly encourage you to read instance variables using direct access but to set them using the property, with a few caveats.

Consider the following class:

@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;

// Convenience for firstName + " " + lastName:
- (NSString*)fullName;
- (void)setFullName:(NSString*)fullName;

The convenience methods fullName and setFullName: might be implemented like this:

- (NSString*)fullName {
    return [NSString stringWithFormat:@"%@ %@",
            self.firstName, self.lastName];

/** The following assumes all full names have exactly 2
 *  parts. The method could be rewritten to support more
 *  exotic names.
- (void)setFullName:(NSString*)fullName {
    NSArray *components =
        [fullName componentsSeparatedByString:@" "];
    self.firstName = [components objectAtIndex:0];
    self.lastName = [components objectAtIndex:1];

In both the getter and the setter, we access the instance variables via the accessor methods, using the property dot syntax. Now suppose that you rewrote both methods to access the instance variables directly:

- (NSString*)fullName {
    return [NSString stringWithFormat:@"%@ %@",
            _firstName, _lastName];

- (void)setFullName:(NSString*)fullName {
    NSArray *components =
        [fullName componentsSeparatedByString:@" "];
    _firstName = [components objectAtIndex:0];
    _lastName = [components objectAtIndex:1];

The two styles have a few differences.

Image Direct access to the instance variables will undoubtedly be faster, as it does not have to go through Objective-C method dispatch (see Item 11). The compiler will emit code that directly accesses the memory where the object’s instance variables are stored.

Image Direct access bypasses the property’s memory-management semantics defined by the setter. For example, if your property is declared as copy, directly setting the instance variable will not cause a copy to be made. The new value will be retained and the old value released.

Image Key-Value Observing (KVO) notifications would not be fired when accessing the instance variables directly. This may or may not be a problem, depending on how you want your objects to behave.

Image Accessing through properties can make it easier to debug issues surrounding a property, since you can add a breakpoint to the getter and/or setter to determine who is accessing the properties and when.

A good compromise is to write instance variables using the setter and to read using direct access. Doing so has the benefit of fast reading and not losing the control of writing via properties. The most important reason for writing via the setter is that you will ensure that the memory-management semantics are upheld. There are, however, a few caveats to that approach.

The first caveat is when values are set within an initializer method. Here, you should always use direct instance variable access, because subclasses could override the setter. Consider that EOCPerson has a subclass EOCSmithPerson that is designed to be used only for people whose last name is “Smith.” This subclass might override the setter for lastName like so:

- (void)setLastName:(NSString*)lastName {
    if (![lastName isEqualToString:@"Smith"]) {
        [NSException raise:NSInvalidArgumentException
                    format:@"Last name must be Smith"];
    self.lastName = lastname;

The base class EOCPerson might set the last name to the empty string in its default initializer. If it did this through the setter, the subclass’s setter would be called and throw an exception. However, there are some cases in which you must use the setterin an initializer. This is when the instance variable is declared within a superclass; you cannot access the instance variable directly anyway, so you must use the setter.

Another caveat is when the property uses lazy initialization. In this case, you have to go via the getter; if you don’t, the instance variable will never get a chance to be initialized. For example, the EOCPerson class might have a property to give access to a complex object representing each person’s brain. If this property is infrequently accessed and expensive to set up, you might initialize it lazily in the getter, like this:

- (EOCBrain*)brain {
    if (!_brain) {
        _brain = [Brain new];
    return _brain;

If you were to access the instance variable directly and the getter had not been called yet, brain would not have been set up, and you would need to call the accessor for all accesses to the brain property.

Things to Remember

Image Prefer to read data directly through instance variables internally and to write data through properties internally.

Image Within initializers and dealloc, always read and write data directly through instance variables.

Image Sometimes, you will need to read data through properties when that data is being lazily initialized.


Effective Objective-C 2.0: Item 43: Know When to Use GCD and When to Use Operation Queues

Item 43: Know When to Use GCD and When to Use Operation Queues GCD is a fantastic technology, but...

Effective Objective-C 2.0: Item 16:Designated Initializer

Item 16: Have a Designated Initializer All objects need to be initialized. When initializing an o...

Effective Objective-C 2.0:Item 25: Always Prefix Category Names on Third-Party Classes

Item 25: Always Prefix Category Names on Third-Party Classes Categories are commonly used to add ...

Effective Objective-C 2.0: Item 41: Prefer Dispatch Queues to Locks for Synchronization

Item 41: Prefer Dispatch Queues to Locks for Synchronization Sometimes in Objective-C, you will com...

Effective Objective-C 2.0:Item 14 Class Object

Item 14: Understand What a Class Object Is Objective-C is extremely dynamic in nature. Item 11 expl...

Effective Objective-C 2.0:Item 20: Prefix Private Method Names

Item 20: Prefix Private Method Names It’s extremely common for a class to do much more than it ap...

Effective Objective-C 2.0: Item 12: Understand Message Forwarding

这点很有意思,理清楚了Message Forward的过程(特别那个例子有意思),但是感觉 具体例子太少了~~ 难道是我没有理解透? Item 12: Understand Messag...

Effective Objective-C 2.0: Item 39: Use Handler Blocks to Reduce Code Separation

Item 39: Use Handler Blocks to Reduce Code Separation A common paradigm in programming a user int...

Effective Objective-C 2.0: Item 35: Use Zombies to Help Debug Memory-Management Problems

Item 35: Use Zombies to Help Debug Memory-Management Problems Debugging memory-management issues ...

Effective Objective-C 2.0: Item 37: Understand Blocks

Effective Objective-C 2.0 介绍Blocks的文章,有些论点比较新颖,觉得不错,值得一看...
您举报文章:Effective Objective-C 2.0:Item 7: Access Instance Variables