Encapsulating Data
封装数据
Properties Encapsulate an Object’s Values
@interface XYZPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
Use Accessor Methods to Get or Set Property Values
//设置属性
NSString *firstName = [somePerson firstName];
[somePerson setFirstName:@"Johnny"];
如果你不想对象被修改则可以加上readonly 代表该属性只有get方法没有set方法
@property (readonly) NSString *fullName;
readonly//只读
//为获取及设置器方法命名,如下,把get方法命名为isFinished(对于BOOL类型的get方法习惯上以is作为开头)
//这样设置后程序将只认得isFinished方法,二不认得getter
@property (getter=isFinished) BOOL finished;
@property (readonly, getter=isFinished) BOOL finished;
Dot Syntax Is a Concise Alternative to Accessor Method Calls
用点来调用类方法和属性
//类似下面这样调用
NSString *firstName=somePerson.firstName; //实例somePerson的firstName属性
somePerson.firstName =@"Johnny";
● Getting a value 获取值
somePerson.firstName 等价于 [somePerson firstName] ?????两种方法取舍,用那种?
● Setting a value设置值
somePerson.firstName= @"Johnny" 等价于 [somePerson setFirstName:@"Johnny"]
Most Properties Are Backed by Instance Variables
大多属性依靠实例变量支持
你可以用以下方法获取属性
- (void)someMethod {
NSString *myString = @"An interesting string";
_someString = myString; //_someString就是实例变量(instance variables)
}
但是一般情况下使用self获取如下
- (void)someMethod {
NSString *myString = @"An interesting string";
self.someString = myString;
// or
[self setSomeString:myString];
}
You Can Customize Synthesized Instance Variable Names
你可以自定义实例变量的名称
//定义
@interface YourClass :NSObject{
NSString * instanceVariableName;
}
@end
//实现
@implementation YourClass
@synthesize propertyName=instanceVariableName;
...
@end
举例如下:
@synthesize firstName= ivar_firstName;
这个例子中属性任然叫 firstName,set,get方法名也不变,不过对应的实例变量名为ivar_firstName
如果你没定义实例变量名如下:
@synthesize firstName
实例变量名会默认和属性名一样叫firstName
You Can Define Instance Variables without Properties
你可以定义实例变量却不定义属性(尽量不要这么用)
实例变量-》外部用
属性-》内部用
如下,要写在interface后的中括号中
//定义接口文件
@interface SomeClass : NSObject {
//在此定义实例变量
NSString *_myNonPropertyInstanceVariable;
}
...
@end
//实现文件
@implementation SomeClass {
//或者在此定义实例变量
NSString *_anotherCustomInstanceVariable;
}
...
@end
你也可以在类扩展中(extension)中定义实例变量
Access Instance Variables Directly from Initializer Methods
在初始化函数中房屋实例变量
一个典型的初始化函数
- (id)init {
//实例化父类其实就是继承父类的成员方法和变量这个必须放在第一行,是实例化类的顺序
self = [super init];
if (self) { //判断非nil
// initialize instance variables here
}
return self;
}
如下例子
如此定义
- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;
如此实现
- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName {
self [super init];
if (self) {
_firstName =aFirstName;
_lastName = aLastName;
}
return self;
}
The Designated Initializer is the Primary Initialization Method
主要初始化函数
如果你有多个初始化函数,则要决定哪个是主要的初始化函数(一般是参数最多的那个作为主要初始化函数,其他初始化函数都调用该函数)
你可以这样定义一个初始化函数作为主初始化函数
//init开头的函数代表的是构造函数、必须返回id或者本类对象
- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName {return [self initWithFirstName:aFirstName lastName:aLastName dateOfBirth:nil];
}
-(id)init {
return [self initWithFirstName:@"John" lastName:@"Doe" dateOfBirth:nil];
}
You Can Implement Custom Accessor Methods
//下面有一个属性
@property (readonly) NSString *fullName;
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
如果你要自定义一个访问器来访问一个实例变量(instance variable)你应该如下写法使用一个“懒惰访问器”
- (XYZObject *)someImportantObject {
if (!_someImportantObject) {
_someImportantObject = [[XYZObject alloc] init];
}
return _someImportantObject;
}
一般请看下,编译器会为属性自动添加实例变量,但是如果你为属性自定义了一个getter和setter方法(readwrite)或者自定义了一个getter方法(readonly)编译器不会自动创建实例变量(instance variable),这种情况下你仍然要创建实例变量的则要如下方法
@synthesize property = _property;
Properties Are Atomic by Default (???????线程概念有待加强)
@interface XYZObject : NSObject
@property NSObject *implicitAtomicObject; // atomic by default 默认就是atomic
@property (atomic) NSObject *explicitAtomicObject; // explicitly marked atomic 显示的定义atomic
@end
@interface XYZObject : NSObject
@property (nonatomic) NSObject *nonatomicObject;
@end
Manage the Object Graph through Ownership and Responsibility
当第一个对象依赖于第二个对象,则说,第一个对象对第二个对象有强引用(strong references )
如图
XYZPerson Object对2个NSString Object有强引用,2个NSString将存在直到XYZPerson对象被重新分配
当XYZPerson对象从内存中被重新分配(deallocated),那么强引用的2个NSString Object也将被重新分配
另一个复杂点的例子
1.2个对象都对@john有强引用
当改变XYZPerson object中firstName的值时候@john任然存在
当再改变XYZBadgeView中firstName的值时候@john被重新分配
Avoid Strong Reference Cycles
2个对象对对方都有强引用,会引起strong reference cycle (强引用循环)会造成程序奔溃,所以需要强引用(strong)和弱引用(weak)结合使用
一个对象只要有一个strong(强引用)就不会被重新分配内存
比如一个对象有一个强引用一个弱引用,强引用被重新分配,改对象也会被重新分配,弱引用会变成指向nil
如下面例子
arc机制概念请看http://onevcat.com/2012/06/arc-hand-by-hand/
Use Strong and Weak Declarations to Manage Ownership
用强/弱引用赖控制权限
//默认情况下定义的属性都是强引用
@property id delegate;
如果要定义一个弱引用类型
@property (weak) id delegate;
Local variables (and non-property instance variables) also maintain strong references to objects by default.This means that the following code will work exactly as you expect:
本地变量和没有属性的实例变量也默认对object保持强引用
@property NSTableView *tableView;
@property id delegate;
@property (weak) id delegate;
//例子
NSDate *originalDate = self.lastModificationDate;
self.lastModificationDate = [NSDate date];
NSLog(@"Last modification date changed from %@ to %@",
originalDate, self.lastModificationDate);
一个变量的强引用保持到改变量被重新分配或者赋值为nil
如果你不希望便利保持强引用那么使用 __weak
NSDate * __weak originalDate = self.lastModificationDate;
self.lastModificationDate = [NSDate date];
这个例子中,当lastModificationDate改变的时候,originalDate会被重新分配并赋值为nil
警告:千万不要像如下定义
NSObject * __weak someObject = [[NSObject alloc] init];
弱引用的强引用
//在一个函数中你可能会需要多次访问一个弱引用
- (void)someMethod {
[self.weakProperty doSomething];
...
[self.weakProperty doSomethingElse];
}
- (void)someMethod {
NSObject *cachedObject = self.weakProperty;
[cachedObject doSomething];
...
[cachedObject doSomethingElse];
}
In this example, the cachedObjectvariable maintains a strong reference to the original weak property valueso that it can’t be deallocated as long ascachedObjectis still in scope (and hasn’t been reassigned anothervalue).
在多线程编程中,弱引用很可能在函数调用中不知不觉被重新分配了,为了严谨,最好如下使用弱引用
NSObject *cachedObject = self.someWeakProperty; //1 定义一个强引用指向弱引用对象
if (cachedObject) { //2 判断强引用的对象是否为空
[someObject doSomethingImportantWith:cachedObject]; //3 使用对象
} //4
cachedObject = nil; //5 把强引用设置为nil,释放弱引用,弱引用被重新分配
In this example, the strong reference is created in line 1, meaning that the object is guaranteed to be alive forthe test and method call. In line 5,cachedObjectis set to nil, thereby giving up the strong reference. If theoriginal object has no other strong references to it at this point, it will be deallocated and someWeakPropertywill be set tonil.
Use Unsafe Unretained References for Some Classes (NSTextView,NSFont、NSColorSpace 等不支持weak引用的类,使用unsafe_unretained类似于weak)
If you need to use a weak reference to one of these classes, you must use an unsafe reference. For a property,this means using theunsafe_unretainedattribute:
//设置非安全非保留属性
@property (unsafe_unretained) NSObject *unsafeProperty;
For variables, you need to use__unsafe_unretained:
//设置非安全非保留变量
NSObject * __unsafe_unretained unsafeReference;
An unsafe reference is similar to a weak reference in that it doesn’t keep its related object alive, but it won’tbe set tonilif the destination object is deallocated. This means that you’ll be left with a dangling pointer tothe memory originally occupied by the now deallocated object, hence the term “unsafe.” Sending a messageto a dangling pointer will result in a crash.
unsafe_unretained 类似于weak,但是区别在于,当unsafe_unretained 指向的对象被重新分配,unsafe_unretained的属性或变量不会被设置成nil,变成了一个指向空引用的指针,会引起程序崩溃
Copy Properties Maintain Their Own Copies (Copy关键字的应用)
修改对象内容却保持引用
//NSMutableString是一个可变的String,与NSString不同,通过其自带方法改变其值(非重新实例化)不会改变其他对象对其的强弱引用
例子如下:
NSMutableString *nameString = [NSMutableString stringWithString:@"John"];
self.badgeView.firstName = nameString;
接下来通过NSMutableString的appendString方法追加字符john
[nameString appendString:@"ny"];
结果是self.badgeView.firstName任然指向的对象与nameString一致都变为了johnny
但是使用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"];
PS:任何要实现copy属性的对象必须支持NSCopying(如下例子)
@interface CommonObj : NSObject<NSCopying>
@end