CG@CPPBLOG

/*=========================================*/
随笔 - 76, 文章 - 39, 评论 - 137, 引用 - 0
数据加载中……

用OBJC编程 3 -Encapsulating Data

用OBJC编程3-Encapsulating Data

@interface XYZPerson :NSObject
@property NSString *firstName;
@property NSString *lastName;
@end

/// ============

NSString *firstName = [somePerson firstName];
[somePerson setFirstName:@"Johnny"];

限定属性为只读,也可限定为readwrite,但这不必,因为缺省如是。
@property (readonly) NSString *fullname;

可以指定属性的访问器名称,多个限定词如下格式
@property (readonly, getter=isFinished) BOOL finished;

使用点语法
NSString *firstName = somePerson.firstName;
// NSString *firstName = [somePerson firstName];
somePerson.firstName = @"Johnny";
// [somePerson setFirstName:@"Johnny"];

大多数属性有一个实例变量。
缺省的读写属性会由编译器自动生成一个实例变量,以下划线开始,如_firstName;
-(void) someMethod{
  NSString *myString = @"An interesting string";
  _someString = myString;
  
// self.someString = myString;
  
// or
  
// [self setSomeString:myString];
}

可以指定实例变量的名字
@implementation YourClass
@synthesize propertyName = instanceVariableName;
@end
// ---- for example

@synthesize firstName = ivar_firstName;

如果你不指定名字,实例变量则和属性同名,前面没有下划线
@synthesize firstName;

如果你并不想提供数值给其它对象,你不必声明一个属性而使用一个实例变量
@interface SomeClass: NSObject{
  NSString *_myNonPropertyInstanceVariable;
}
@end

@implementation SomeClass{
  NSString *_anotherCustomInstanceVariable;
}

在初始化方法里访问实例变量
Setter方法会有附加效果。它们可能触发KVC通知,或者完成你定制的方法。
你应该在初始化方法里直接访问实例变量,因为对象还没有初始化完成。甚至你不应该提供定制的访问器方法给你的类提供附加效果。这样将来的子类可以很好的override这个行为。
一个典型的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];
}

如果你需要在访问器里访问实例变量,那应该直接访问。例子里延迟初始化一个对象,lazy accessor。
- (XYZObject *)someImportantObject {
  
if(!_someImportantObject){
    _someImportantObject = [[XYZObject alloc] init];
  }
  
return _someImportantObject;
}

编译器会自动synthesize一个实例变量。至少一个访问方法。如果你为readwrite属性实现了getter和setter,或者为readonly实现了getter。编译器认为你想控制属性实现,也不会再为你自动生成一个实例变量。因此,如果你仍然需要一个实例变量,你需要手动synthesize
@synthesize property = _property;

属性缺省是原子性的。atomic
@interface XYZObject : NSObject
@property NSObject *implicitAtomObject;                  // 缺省是atomic
@property (atomic) NSObject *explicitAtomicObject;       // 指明atomic
@end
缺省访问器已经解决了多线程并发的问题。

如果你定制了一个atomic, readwrite的属性的setter,而让编译器自动生成getter,将会得到一个编译时警告。

你可以声明nonatomic属性,因为不需要guarantee,处理并发,因此它的访问器比atomic属性更快。

属性的原子性并不意味着对象是线程安全的。例如firstName和LastName。

管理对象的生命周期,对象是通过指针来访问,内存是动态申请的,指针变量的生命周期不代表对象的证明周期。strong reference意味着对象和另一个对象的生命周期一样长。
属性缺省是强引用,可以指定weak。本地变量都是强引用,如果你不希望维护一个强引用,可以使用__weak
@property (weak) id delegate;
// ---------
NSObject * __weak weakVariable;

弱引用会带来不安全的行为,因为变量可能会被置为nil。
一些Cocoa类不能声明为弱引用,包括NSTextView, NSFont, NSColorSpace等,如果你需要使用这些类的一个弱引用,你需要一个unsafe_unretained声明。
@property (unsafe_unretained) NSObject *unsafePropery;
// ------------
NSObject * __unsafe_unretained unsafeReference;
unsafe引用类似weak引用,但当对象释放时,它不会被置为nil,因此你可能会持有一个悬挂指针,指向一个未知内存,向它发消息可能会导致崩溃。

copy属性
@interface XYZBadgeView : NSView
@property NSString *firstName;
@peoperty NSString *lastName;
@end

如果你这样做
NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
// ----
[nameString appendString:@"ny"];
这样firstName将指向一个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”,不会发生变化

一个被声明为copy的对象必须支持NSCopying协议。如果你要直接set一个copy属性的实例变量,例如在初始化方法里,一定要设置原始对象的copy
-(id)initWithSomeOriginalString:(NSString *)aString{
  self = [super init];
  
if(self){
     _instanceVariableForCopyProperty = [aString copy];
  }
  
return self;
}


posted on 2013-11-20 16:49 cuigang 阅读(260) 评论(0)  编辑 收藏 引用 所属分类: OBJC


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理