1. @property:
1.1. 屬性的聲明及實現:
之前的@property只是負責setter和getter的聲明,需程序員手動實現方法 :
@property int age; @synthesize age = _age;
現在的@property會生成實例變量及setter和getter方法的聲明及實現
// 聲明的時候:
@interface Person : NSObject
{
int _age;
int _height;
double _weight;
NSString *_name;
}
@property int age;
@property int height;
@property double weight;
@property (copy)NSString *name;
@end
// 實現的時候:
@implementation Person
// @synthesize會自動實現setter和getter方法
@synthesize age = _age; // 會自動訪問_age
@synthesize name = _name;
@synthesize height = _height;
@synthesize weight = _weight;
@end
會完成三件事:
1--聲明setter和getter方法
2--生成成員變量(不需要在聲明成員變量啦~ ~)
3--實現setter和getter方法
因爲@property生成的成員變量是私有的,子類不能直接訪問,只能通過setter和getter方法訪問
自己聲明的成員變量默認是protected,子類可以訪問
可以將類型一致的寫在同一行,用逗號隔開。(儘量不要寫在一行)
若是在.h 文件中沒有聲明任何成員變量,@synthesize age = _age 訪問_age時,若不存在,會自動生成一個成員變量_age;可見度爲@private。
1.2. 屬性的屬性/@property的參數:
1.2.1. 有三大類:原子屬性,讀寫屬性,set方法處理
1. 原子屬性:
atomic:對屬性加鎖,多線程下線程安全,默認值,速度比nonatomic慢
nonatomic:對屬性不加鎖,多線程下不安全,但是速度快 (就是普通的setter getter方法)
2. 讀寫屬性:
readwrite:生成getter、setter,默認值
readonly:只生成getter方法
3. set方法處理:
assign:直接賦值,默認值(非對象類型:基本數據類型使用)
retain:先release原來的值,再retain新值(在一個類中有關聯其他對象的時候,OC對象類型:NSString,NSArray...使用)- - -內存優化
copy:先release原來的值,再copy新值(所有遵守NSCopying協議的對象使用)- - -內存優化
assign實際生成的setter方法如下:(直接賦值)
- (void)setName:(NSString *)name{
_name = name;
}
retain實際生成的setter方法如下:
- (void)setName:(NSString *)name{
if(_name != name){
[_name release];
_name = [name retain];
}
}
copy實際生成的setter方法如下:
- (void)setName:(NSString *)name{
if(_name != name){
[_name release];
_name = [name copy];
}
}
其他對象類型使用retain NSString,block使用copy吧在@property後面加屬性setter getter 相當於給系統生成的setter和getter方法重命名而已:
@property (nonatomic,assign,setter=isVip:,getter=isVip);
1.2.2. copy和retain的區別:
@property (nonatomic,retain)NSString *name:
retain是在你聲明的字符串上進行修改,下面的例子:第一次將str賦給t.name後,對str進行修改,即使不用再次賦值,t.name的內容也會跟着str改變
@autoreleasepool {
Teacher *t = [[Teacher alloc] init];
NSMutableString *str = [NSMutableString string];
[str appendString:@"豬八戒"];
t.name = str;
[str appendString:@"二師兄"];
NSLog(@"%@",t.name);
[t release];
}
結果打印顯示:
2015-10-07 11:29:43.588 Lesson-OC-8-Property[624:61344] 豬八戒二師兄
Program ended with exit code: 0
@property (nonatomic,copy)NSString *name:
copy是先拷貝一份str的內容,賦值給t.name,然後對str進行修改的時候,並不會影響t.name的值
@autoreleasepool {
Teacher *t = [[Teacher alloc] init];
NSMutableString *str = [NSMutableString string];
[str appendString:@"豬八戒"];
t.name = str;
[str appendString:@"二師兄"];
NSLog(@"%@",t.name);
[t release];
}
結果打印顯示:
2015-10-07 11:38:11.722 Lesson-OC-8-Property[691:64925] 豬八戒
Program ended with exit code: 0
2. KVC(key value coding):鍵值編碼
KVC是一種間接訪問實例變量的方法。
KVC操作方法由NSKeyValueCoding協議提供:
NSObject實現了這個協議,也就是OC中所有的類都支持KVC操作
2.1. 常用的KVC操作方法:
動態設置(修改值):
setValue:屬性值 forKey:屬性名 (用於簡單的路徑)
setValue:屬性值 forKeyPath:屬性路徑 (用於複合路徑)---類.類.屬性
動態讀取(獲取值):
valueForKey:屬性名
valueForKeyPath:屬性名
2.2. KVC查找規則:
動態設置屬性:
優先考慮調用setter,沒有該方法則搜索_age成員變量,如果還是沒有,則調用:setValue: forUndefinedKey:方法
動態讀取屬性:
優先考慮調用age的getter方法,沒有該方法則搜索_age成員變量,如果還是沒有,則調用:valueForUndefinedKey:方法
注:無論這些方法是私有還是其他,均可正常訪問
@autoreleasepool {
Person *p = [[Person alloc] init];
// p.name = @"Henry";
// 訪問私有變量age:---動態設置(簡單路徑)
[p setValue:@"Henry" forKey:@"name"]; // 給name賦值爲@"Henry"
[p setValue:@"male" forKey:@"sex"];
[p setValue:@28 forKey:@"age"];// 在本題中age是私有變量,但是通過這個方法是可以給age賦值的!!!
[p showMessage];// 這個方法用來顯示name sex age
NSLog(@"%@", [p valueForKey:@"name"]);
Account *account1 = [[Account alloc] init];
[p setValue:account1 forKey:@"account"];
p.account.balance = 10.8;
//@"account.balance"是因爲Person類裏包含了實例變量Account *account 要想給account裏的balance賦值,需要根據路徑找到它
[p setValue:@10.09 forKey:@"account.balance"];
NSLog(@"%.2f", [[p valueForKeyPath:@"account.balance"] floatValue]);
// setValuesForKeysWithDictionary:就是用來將一個字典進行賦值
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Shelock", @"name", @"male", @"sex", @"26", @"age", nil];
[p setValuesForKeysWithDictionary:dic];
NSLog(@"%@", p);
[p release];
[account1 release];
}