用OBJC編程3-Encapsulating Data
@interface XYZPerson :NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
/// ============
NSString *firstName = [somePerson firstName];
[somePerson setFirstName:@"Johnny"];
限定屬性為只讀,也可限定為readwrite,但這不必,因?yàn)槿笔∪缡恰?/span>
@property (readonly) NSString *fullname;
可以指定屬性的訪問器名稱,多個(gè)限定詞如下格式
@property (readonly, getter=isFinished) BOOL finished;
使用點(diǎn)語法
NSString *firstName = somePerson.firstName;
// NSString *firstName = [somePerson firstName];
somePerson.firstName = @"Johnny";
// [somePerson setFirstName:@"Johnny"];
大多數(shù)屬性有一個(gè)實(shí)例變量。
缺省的讀寫屬性會(huì)由編譯器自動(dòng)生成一個(gè)實(shí)例變量,以下劃線開始,如_firstName;
-(void) someMethod{
NSString *myString = @"An interesting string";
_someString = myString;
// self.someString = myString;
// or
// [self setSomeString:myString];
}
可以指定實(shí)例變量的名字
@implementation YourClass
@synthesize propertyName = instanceVariableName;
@end
// ---- for example
@synthesize firstName = ivar_firstName;
如果你不指定名字,實(shí)例變量則和屬性同名,前面沒有下劃線
@synthesize firstName;
如果你并不想提供數(shù)值給其它對(duì)象,你不必聲明一個(gè)屬性而使用一個(gè)實(shí)例變量
@interface SomeClass: NSObject{
NSString *_myNonPropertyInstanceVariable;
}
@end
@implementation SomeClass{
NSString *_anotherCustomInstanceVariable;
}
在初始化方法里訪問實(shí)例變量
Setter方法會(huì)有附加效果。它們可能觸發(fā)KVC通知,或者完成你定制的方法。
你應(yīng)該在初始化方法里直接訪問實(shí)例變量,因?yàn)閷?duì)象還沒有初始化完成。甚至你不應(yīng)該提供定制的訪問器方法給你的類提供附加效果。這樣將來的子類可以很好的override這個(gè)行為。
一個(gè)典型的init方法如下
-(id)init{
self = [super init];
if(self){
// initialize instance variables here
}
return self;
}
可以指定初始化方法
-(id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName{
self = [super init];
if(self){
_firstName = aFirstName;
_lastName = aLastName;
}
return self;
}
可以指定訪問方法
@property (readonly) NSString *fullName;
// -------------
-(NSString *)fullName{
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
如果你需要在訪問器里訪問實(shí)例變量,那應(yīng)該直接訪問。例子里延遲初始化一個(gè)對(duì)象,lazy accessor。
- (XYZObject *)someImportantObject {
if(!_someImportantObject){
_someImportantObject = [[XYZObject alloc] init];
}
return _someImportantObject;
}
編譯器會(huì)自動(dòng)synthesize一個(gè)實(shí)例變量。至少一個(gè)訪問方法。如果你為readwrite屬性實(shí)現(xiàn)了getter和setter,或者為readonly實(shí)現(xiàn)了getter。編譯器認(rèn)為你想控制屬性實(shí)現(xiàn),也不會(huì)再為你自動(dòng)生成一個(gè)實(shí)例變量。因此,如果你仍然需要一個(gè)實(shí)例變量,你需要手動(dòng)synthesize
@synthesize property = _property;
屬性缺省是原子性的。atomic
@interface XYZObject : NSObject
@property NSObject *implicitAtomObject; // 缺省是atomic
@property (atomic) NSObject *explicitAtomicObject; // 指明atomic
@end
缺省訪問器已經(jīng)解決了多線程并發(fā)的問題。
如果你定制了一個(gè)atomic, readwrite的屬性的setter,而讓編譯器自動(dòng)生成getter,將會(huì)得到一個(gè)編譯時(shí)警告。
你可以聲明nonatomic屬性,因?yàn)椴恍枰猤uarantee,處理并發(fā),因此它的訪問器比atomic屬性更快。
屬性的原子性并不意味著對(duì)象是線程安全的。例如firstName和LastName。
管理對(duì)象的生命周期,對(duì)象是通過指針來訪問,內(nèi)存是動(dòng)態(tài)申請(qǐng)的,指針變量的生命周期不代表對(duì)象的證明周期。strong reference意味著對(duì)象和另一個(gè)對(duì)象的生命周期一樣長(zhǎng)。
屬性缺省是強(qiáng)引用,可以指定weak。本地變量都是強(qiáng)引用,如果你不希望維護(hù)一個(gè)強(qiáng)引用,可以使用__weak
@property (weak) id delegate;
// ---------
NSObject * __weak weakVariable;
弱引用會(huì)帶來不安全的行為,因?yàn)樽兞靠赡軙?huì)被置為nil。
一些Cocoa類不能聲明為弱引用,包括NSTextView, NSFont, NSColorSpace等,如果你需要使用這些類的一個(gè)弱引用,你需要一個(gè)unsafe_unretained聲明。
@property (unsafe_unretained) NSObject *unsafePropery;
// ------------
NSObject * __unsafe_unretained unsafeReference;
unsafe引用類似weak引用,但當(dāng)對(duì)象釋放時(shí),它不會(huì)被置為nil,因此你可能會(huì)持有一個(gè)懸掛指針,指向一個(gè)未知內(nèi)存,向它發(fā)消息可能會(huì)導(dǎo)致崩潰。
copy屬性
@interface XYZBadgeView : NSView
@property NSString *firstName;
@peoperty NSString *lastName;
@end
如果你這樣做
NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
// ----
[nameString appendString:@"ny"];
這樣firstName將指向一個(gè)NSMutableString,它的值可以改變了,你可以增加copy聲明,避免這種情況
@interface XYZbadgeView : NSView
@property (copy) NSString *firstName;
@property (copy) NSString *lastName;
@end
// --------------------
NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
// ----
[nameString appendString:@"ny"];
這樣firstName仍然是“John”,不會(huì)發(fā)生變化
一個(gè)被聲明為copy的對(duì)象必須支持NSCopying協(xié)議。如果你要直接set一個(gè)copy屬性的實(shí)例變量,例如在初始化方法里,一定要設(shè)置原始對(duì)象的copy
-(id)initWithSomeOriginalString:(NSString *)aString{
self = [super init];
if(self){
_instanceVariableForCopyProperty = [aString copy];
}
return self;
}