开发者

Objective-C, interface declarations with properties

In the following common sample,

////
@interface MyObject : NSObject
{
 @public
  NSString * myString_;
}

@property (assign) NSString * myString;
@end

@implementation MyObject
@synthesize myString开发者_如何转开发 = myString_;
@end
////

why declare myString_ in the interface at all?

I ask because we can still get and set myString in the implementation using self.myString, [self myString], self.myString = ... and [self setMyString:...] and in fact we must if instead it's being retained.


This is a matter of preference/convention for some. By default, doing:

@property (assign) NSString * myString;

...followed by:

@synthesize myString;

...will give you three things. You get a setter method that can be accessed as self.myString = @"newValue" or [self setMyString:@"newValue"], a getter method that can be accessed as NSString* temp = self.myString or NSString* temp = [self myString], and an instance variable named myString that be be accessed directly inside of your class (i.e. without going through the getter and setter) and used to set and get the property value, and which is used internally to back the property.

If you like you can do @synthesize myString = someOtherVarName, and then you still get the setters and getters just as before, but instead of the myString instance variable the someOtherVarName instance variable is used to back the property, and no myString variable is created.

So why ever use the more verbose syntax? There is never any case that requires that you do so, but some people prefer to do so when dealing with properties that are declared retain or copy. The reason for this being that setting a property declared retain or copy via its generated setter method will affect the retain-count of the object being set/unset. Doing the same thing by accessing the instance variable directly will not.

So by aliasing the instance variable to something else, you can make a distinction in the code along the lines of "anything that does xxx.myString = Y is modifying the retain count, while anything that does someOtherVarName = Y is not". Again, it's not necessary to do this, but some people prefer to.


You should be able to skip it. Modern compilers allow that.

When you define a property, you are actually declaring how the getter and setter methods are constructed for a particular instance variable. Earlier it needed the instance variable to be defined so you declared it. It also allowed the property name to differ from the instance variable name via @synthesize myProperty = myIVar;. Now you don't need to do this as the modern compilers generate the instance variable for you.

The dot syntax is actually a convenience thing as you would've noticed. It doesn't directly refer to the instance variable but the methods myProperty and setMyProperty:. You can even call myArray.count where count isn't a property (I wouldn't recommend it even though lot of people seem to like it).

While there is a difference between the two, the gap seems to be slowly closing.


That's just a problem about point of view. If you access ivar directly, it's you're accessing it internally. If you're using property, you're not accessing ivar (semantically). You're using accessing method of the object. So you're handling the self as like external object which the internal is unknown.

This is encapsulation problem of Object-Oriented paradigm.

And I recommend some tricks when using properties.

  1. The ivar declaration is optional, not required. Compiler will generate it automatically.
  2. You should set the ivar as @protected or @private to encapsulate it correctly. (at least there is no reasonable reason)
  3. I recommend to use nonatomic if you don't need threading lock when accessing the property. Threading lock will decrease performance greatly, and may cause strange behavior in concurrent execution code.

You can use this code to do same thing.

@interface MyObject : NSObject
@property (assign,nonatomic) NSString * myString;
@end

@implementation MyObject
@synthesize myString;
@end

And this will be transformed roughly something like this.

@interface MyObject : NSObject
{
    @private
    NSString* myString; // Ivar generated automatically by compiler
}
@end

@implementation MyObject
// Methods with thread synchronization locking generated automatically by compiler.
- (NSString*)myString { @synchronized(self) { return myString; } }
- (void)setMyString:(NSString*)newMyString { @synchronized(self){ myString = newMyString; } }
@end

In fact, I'm not sure about synchronization lock with assign behavior directive, but it's always better setting it nonatomic explicitly. Compiler may optimize it with atomic operation instruction instead of locking.

Here is reference document about the properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17


With the modern Obj-C runtime, declaring the ivar is more of a formality than anything else. However, there are some memory management things to keep in mind.

First, the property declaration for an object type is usually retain, or for strings it may be copy. In either case, the new object is retained.

Given the following code:

NSString *string = [[NSString alloc] init];
myString_ = string;
self.myString = string;    // If the property was retain or copy

The second assignment would leak; the first would not. This is because the property would retain something that already has a retain count of 1—it is now at 2. When you release the property in dealloc, the count goes to 1, not 0, so it won't be released. With the first option, however, the retain count stays at 1, so dealloc brings it down to 0.

In your example, leaving the property as assign will make the ivar declaration a formality.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜