//属性的属性
属性定义在一个 .h文件里,在这个.h文件里可以定义实例变量(就是这个类的特征),也可以通过 @protery(属性约束关键字) 属性名字类型 属性名 来定义一些属性,在property里面重置setter或者getter的方法名(例如:@property(readwrite,setter=haha:,getter=dedaomingnzi) NSString *name;)属性的约束有:读写约束(readonly、readwrite)原子约束(atomic)非原子约束
也可以在.m文件里定义当前类的私有的实例变量和私有方法(私有方法在声明的时候也在.m文件里声明,如果在.h文件里声明,那就是能够提供给外部接口的方法了)这就是一个类的延展(Extension);如果一个我们看不到源代码的类,我们需要他的一些方法的实现,但是该类没有实现,那就建立一个分类 ,注意分类只能仅仅是添加类的方法,category;
/*
1.读写特性(写在 property 关键字后面的 括号内 如果不设置的话,那就是默认的readwrite)
readonly(只能去读(获取值)不能写,只有getter方法,只能获取值,不能写)
readwrite(默认的特性 既可以读又可以写,相当于他有getter和setter方法,可以访问( 值)也可以赋值)
setter= 的用法:他是设置 setter 方法的名字 例如:@property(readwrite,setter = haha:) NSString *name;我们在使用的时候,直接 [对象 haha:消息];
getter= 设置getter的方法名字,也就是修改 getter 方法的名字
2.原子特性
atomic 原子特性
nonatomic 非原子特性
原子特性 与 非原子特性 的区别:在我们用setter getter 方法的时候,系统默认的是原子特性,原子特性是保护我们的线程安全(多加了个上锁 开锁的过程)好处:保护属性的安全 坏处:占用系统资源
非原子特性:没有做线程处理,(只是简单的生成setter 和 getter 方法)(苹果推荐使用的特性)
线程:就是同时的做多件事
3.语义特性
assign (系统默认的特性)通常使用于基本类型 NSInterger,CGFloat,在取值与值的时候,只是简单的取值与赋值操作(就是里面自己写了 _name = name 的方法)
retain 通常使用于 所有的对象类型 setter getter 方法就会自动生成内存优化的的代码
copy 通常适用于对象类型,服从NSCoping 协议的对象类型才会使用 例如 NSString
**/
什么是KVC
//KVC 就是三个单词的简写 (key-value-coding)键值编码
//为实例变量赋值的另一种机制,是一种间接访问对象的实例变量的机制
Person * per = [[Person alloc]init];
//在外部无法访问受保护的实例变量,也没用定义setter getter 这时候可以通过KVC
//setValue:forKey:间接的给实例变量赋值 取值就是[对象 valueForKey:@“key”];
//赋值过程
//1.系统先检查有没有name这个实例变量
//2.如果没有,检查有没有同名的带有下滑线的实例变量,_name.如果找到的话,就为他赋值
//3.如果还没有的话就准备crash,他就会自动的调用一个方法,setValue:forUndefinedKey:这个方法
[per setValue:@"Niujianwei" forKey:@"na"];
[per setValue:@"男" forKey:@"gender"];
[per setValue:@"Niuni" forKey:@"id"];
[per setValue:@"sd" forKey:@"name1"];
NSLog(@"%@",[per valueForKey:@"na"]);
//一般通过KVC方法我们一般都要重写 setValue:forUndefinedKey 和 valueForUndefinedKey 两个方法
NSLog(@"%@",per);
//有时候我们为了避免出错 吧 id 改为 ID 因为 id 可能代表所有类型
// NSString * ID
//有时候通过间接的找不到id 就找 _id 再找不到 就走报错的处理路线(注意报错的路线也可以给某个变量赋值)
//对应的取值过程
//1.先检查有没有 name 这个实例变量
//2.如果没有,检查有没有和他同名的带有下划线的实例变量 _name ,有的话就直接取值
//3.如果没有的话,直接走我们的自动调用valueForUndefinedKey:方法
//下面方法也是给实例变量赋值
// per setValue:<#(id)#> forKeyPath:<#(NSString *)#>
Phone * phone = [[Phone alloc]init];
[phone setValue:@"iphone" forKey:@"brand"];//间接为手机赋值
[per setValue:phone forKeyPath:@"phone"];
NSLog(@"%@",[per valueForKey:@"phone"]);
NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);//通过路径
[per setValue:@"小米手机" forKeyPath:@"phone.brand"];
NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);
setValue: forKey setValue: forKeyPath:
这段代码有什么问题吗:
@implementation Person
- (void)setAge:(int)newAge {
self.age = newAge;//点语法用在”=“的左边,就是setter 方法,self是调用当前setter 方法的对象,这样就导致了死循环,所以不能这样使用哦
}
@end
什么是Protocol?什么是代理?写一个委托的interface?委托的property声明用什么属性?为什么?
协议提供了一组方法,但是并不负责实现,如果一个类遵循了某个协议,并且实现了协议里面的方法,那么我们称这个类就是遵循了某个协议的代理。属性的声明使用assign,防止出现循环引用的问题。
分别描述类别(categories)和延展(extensions)是什么?以及两者的区别?继承和类别在实现中有何区别?为什么Category只能为对象添加方法,却不能添加成员变量?
category类目:在不知道源码的情况下为一个类扩展方法,extension:为一个类声明私有方法和变量。
继承是创建了一个新的类,而类别只是对类的一个扩展,还是之前的类。
类目的作用就是为已知的类添加方法。
KVC键值编码,可以直接通过字符串的名字(key)来间接访问属性的机制,而不是通过调用getter和setter方法访问。
对应代码:
// // main.m #import <Foundation/Foundation.h> #import "Person.h" #import "Phone.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //KVC 就是三个单词的简写 (key-value-coding)键值编码 //为实例变量赋值的另一种机制,是一种间接访问对象的实例变量的机制 Person * per = [[Person alloc]init]; //在外部无法访问受保护的实例变量,也没用定义setter getter 这时候可以通过KVC //setValue:forKey:间接的给实例变量赋值 //赋值过程 //1.系统先检查有没有name这个实例变量 //2.如果没有,检查有没有同名的带有下滑线的实例变量,_name.如果找到的话,就为他赋值 //3.如果还没有的话就准备crash,他就会自动的调用一个方法,setValue:forUndefinedKey:这个方法 [per setValue:@"Niujianwei" forKey:@"na"]; [per setValue:@"男" forKey:@"gender"]; [per setValue:@"Niuni" forKey:@"id"]; [per setValue:@"sd" forKey:@"name1"]; NSLog(@"%@",[per valueForKey:@"na"]); //一般通过KVC方法我们一般都要重写 setValue:forUndefinedKey 和 valueForUndefinedKey 两个方法 NSLog(@"%@",per); //有时候我们为了避免出错 吧 id 改为 ID 因为 id 可能代表所有类型 // NSString * ID //有时候通过间接的找不到id 就找 _id 再找不到 就走报错的处理路线(注意报错的路线也可以给某个变量赋值) //对应的取值过程 //1.先检查有没有 name 这个实例变量 //2.如果没有,检查有没有和他同名的带有下划线的实例变量 _name ,有的话就直接取值 //3.如果没有的话,直接走我们的自动调用valueForUndefinedKey:方法 //下面方法也是给实例变量赋值 // per setValue:<#(id)#> forKeyPath:(NSString *) Phone * phone = [[Phone alloc]init]; //为phone的实例变量brand赋值 [phone setValue:@"iphone" forKey:@"brand"]; //通过路径:间接为手机赋值 [per setValue:phone forKeyPath:@"phone"]; NSLog(@"%@",[per valueForKey:@"phone"]); NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);//通过路径 //通过路径:为per的实例变量phone的实例变量brand赋值 [per setValue:@"小米手机" forKeyPath:@"phone.brand"]; NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]); // per setValuesForKeysWithDictionary:<#(NSDictionary *)#> } return 0; }
// // Person.h #import <Foundation/Foundation.h> #import "Phone.h" @interface Person : NSObject { NSString *_name; NSString *_gender; NSString *_ID; Phone * phone; } -(id)description; @end
// // Person.m // #import "Person.h" @implementation Person -(id)description{ return [[NSString alloc]initWithFormat:@"%@ %@ ",_name,_gender]; } //如果 key 不存在的时候,要崩溃的时候,就执行此方法,通常用于错误的处理 - (void)setValue:(id)value forUndefinedKey:(NSString *)key{ NSLog(@"---undefined key-----"); if ([key isEqualToString:@"name1"]) { _name = @"无名"; } //有时候我们为了避免出错 吧 id 改为 ID 因为 id 可能代表所有类型 // NSString * ID if ([key isEqualToString:@"id"]) { _ID = value;//把key 对应的 value 赋值给 ID } } //如果 key 不存在就会走这个方法 valueForUndefinedKey 有返回值 - (id)valueForUndefinedKey:(NSString *)key{ //这里一般用作错误处理 if ([key isEqualToString:@"na"]) { return @"不存在"; } return nil; } @end
// // Phone.h #import <Foundation/Foundation.h> @interface Phone : NSObject { NSString *_brand; } @end
// // Phone.m #import "Phone.h" @implementation Phone @end
为什么在定义属性的时候,定义一个
@property(readwrite,setter=haha:,getter=dedaomingnzi,copy) NSString *name;
代码:
1 // 2 // main.m 3 // Property 9 #import <Foundation/Foundation.h> 10 #import "Person.h" 11 #import "Phone.h" 12 #import "Stuednt.h" 13 #import "GrilFrinend.h" 14 15 int main(int argc, const char * argv[]) { 16 @autoreleasepool { 17 // insert code here... 18 NSLog(@"Hello, World!"); 19 Person * per = [[Person alloc]init]; 20 // [per haha:@"牛建伟"];//属性里面写成 readonly 21 //如果不给stter重新命名的话,那这里就是[per setName:@"牛建伟"] 22 NSLog(@"%@",[per dedaomingnzi]);//这里修改了getter 方法名 23 24 //点语法(把实例变量定义成属性之后) 25 //在等号的左边就是setter 方法 在等号的右边就是 getter 方法 26 //取值 对应的是 getter 方法 27 ;//[per dedaomingnzi]; 28 NSLog(@"%@ %ld %@",per.dedaomingnzi,per.age,per.gender); 29 // per.age; //[per age]; 30 // per.gender;//[per gender]; 31 //赋值 对应的是setter 方法 32 per.age = 23; 33 per.gender = @"woman"; 34 per.name = @"xinmingzi"; 35 36 //创建一个Student 类 有四个属性 初始化方法 以及便利构造器方法 37 Stuednt * stu = [[Stuednt alloc]initWithName:@"十一" gender:@"man" age:23 hobby:@"flootball"]; 38 NSLog(@"%@",[stu description]); 39 Phone * phone = [[Phone alloc]initWithBrand:@"苹果6"]; 40 stu.phone = phone; 41 42 //@synthesize 查阅 KVC 43 44 } 45 return 0; 46 }
1 // 2 // Person.h 3 // Property 9 #import <Foundation/Foundation.h> 10 11 @interface Person : NSObject 12 { 13 // NSString *_name; 14 // NSString *_gender; 15 // NSInteger _age; 16 } 17 //属性 作用:1.自动生成(已经设定的实例变量)setter getter 包括声明和实现的部分,自动生成 _属性 2.如果没有定义实例变量就会自动生成实例变量(实例变量就是 _属性名) 18 // 属性的类型 属性名 19 @property(readwrite,setter=haha:,getter=dedaomingnzi,copy) NSString *name; 20 @property(atomic,copy) NSString *gender; 21 @property(readwrite,assign)NSInteger age; 22 //属性的属性 23 /* 24 1.读写特性(写在 property 关键字后面的 括号内 如果不设置的话,那就是默认的readwrite) 25 readonly(只能去读(获取值)不能写,只有getter方法,只能获取值,不能写) 26 readwrite(默认的特性 既可以读又可以写,相当于他有getter和setter方法,可以访问(取值)也可以赋值) 27 setter= 的用法:他是设置 setter 方法的名字 例如:@property(readwrite,setter = haha:) NSString *name;我们在使用的时候,直接 [对象 haha:消息]; 28 getter= 设置getter的方法名字,也就是修改 getter 方法的名字 29 30 2.原子特性 31 atomic 原子特性(加了一个线程锁) 32 nonatomic 非原子特性 33 原子特性 与 非原子特性 的区别:在我们用setter getter 方法的时候,系统默认的是原子特性,原子特性是保护我们的线程安全(多加了个上锁 开锁的过程)好处:保护属性的安全 坏处:占用系统资源 34 非原子特性:没有做线程处理,(只是简单的生成setter 和 getter 方法)(苹果推荐使用的特性) 35 线程:就是同时的做多件事 36 37 3.语义特性 38 assign (系统默认的特性)通常使用于基本类型 NSInterger,CGFloat,在取值与赋值的时候,只是简单的取值与赋值操作(就是里面自己写了 _name = name 的方法) 39 retain 通常使用于 所有的对象类型 setter getter 方法就会自动生成内存优化的的代码 40 copy 通常适用于对象类型,服从NSCoping 协议的对象类型才会使用 例如 NSString 41 42 **/ 43 44 //初始化 45 - (id)initWithName:(NSString *)name 46 gender:(NSString *)gender 47 age:(NSInteger)age; 48 // 49 50 //便利构造器 51 @end
1 // 2 // Person.m 3 // Property 9 #import "Person.h" 10 11 @implementation Person 12 13 //初始化 14 - (id)initWithName:(NSString *)name 15 gender:(NSString *)gender 16 age:(NSInteger)age{ 17 self = [self init]; 18 if (self) { 19 // _name = name;//在定义 @protery之后自动生名的 20 // _gender = gender; 21 // _age = age; 22 self.name = name;//在定义的时候一般都定义了是copy retain方法,所以在后面使用的时候一般都用点语法,这样可以在使用的时候就优化 23 self.age = age; 24 self.gender = gender; 25 } 26 return self; 27 } 28 29 //属性的实现 name = _name 的含义:属性name 的setter 和 getter 方法在操作_name实例变量的时候,等号的右边可以随意写,但是系统的机制会先检查,.h中有没有对应的名称的实例变量,如果没有就自动生成一个,生成的默认是一个私有的实例变量 30 //在IOS6.0之后属性可以不写,编译器会自动生成对应方法的实现,操作的实例变量是跟属性同名的 _属性名 的实例变量 31 @synthesize name = _name; 32 33 34 //内存管理两种 1.垃圾回收机制 2.引用计数机制 35 - (void)setName:(NSString *)name{ 36 if (_name != name) {//判断 37 // 内存方面的三大问题:野指针、过度释放、内存泄露 38 [_name release]; 39 _name = [name retain]; 40 41 } 42 } 43 //经过内存优化的getter方法 (了解) 44 - (NSString *)name{ 45 return [[_name retain]autorelease];; 46 } 47 48 @end
1 // 2 // Stuednt.h 3 // Property 4 9 #import <Foundation/Foundation.h> 10 @class Phone; 11 12 @interface Stuednt : NSObject 13 @property (nonatomic,readwrite,copy)NSString * name;//如果这里定义的时候加了一个_则对应生成的实例变量的时候就会有两个_,默认生成的属性名是 _属性 14 @property (nonatomic,readwrite,copy)NSString *gender; 15 @property (nonatomic,readwrite,assign)NSInteger age; 16 @property (nonatomic,readwrite,copy)NSString *hobby; 17 @property (nonatomic,retain)Phone * phone; 18 19 //初始化 20 - (id)initWithName:(NSString *)name 21 gender:(NSString *)gender 22 age:(NSInteger)age 23 hobby:(NSString *)hobby; 24 //便利构造器 25 + (id)initWithName:(NSString *)name 26 gender:(NSString *)gender 27 age:(NSInteger)age 28 hobby:(NSString *)hobby; 29 -(NSString *)description; 30 @end
1 // 2 // Stuednt.m 3 // Property 4 9 #import "Stuednt.h" 10 #import "Phone.h" 11 12 @implementation Stuednt 13 //初始化 14 - (id)initWithName:(NSString *)name 15 gender:(NSString *)gender 16 age:(NSInteger)age 17 hobby:(NSString *)hobby{ 18 self = [self init]; 19 if (self) { 20 self.name = name; 21 self.gender = gender; 22 self.age = age; 23 self.hobby = hobby; 24 } 25 return self; 26 } 27 //便利构造器 28 + (id)initWithName:(NSString *)name 29 gender:(NSString *)gender 30 age:(NSInteger)age 31 hobby:(NSString *)hobby{ 32 Stuednt * stu = [[Stuednt alloc]initWithName:name gender:gender age:age hobby:hobby]; 33 return stu; 34 } 35 //重写 description 方法,返回当通过%@打印该对象类型的时候,想在控制台输出的内容 36 -(NSString *)description{ 37 // return [[NSString alloc]initWithFormat:@"name:%@ gender:%@ age:%ld hobby:%@",_name,_gender,_age,_hobby]; 38 return [[NSString alloc]initWithFormat:@"name:%@ gender:%@ age:%ld hobby:%@",self.name,self.gender,self.age,self.hobby];//这里最好用点语法,因为点语法是一个setter getter 39 } 40 @synthesize name = _name; 41 //getter方法内部的实现 42 - (NSString *)name{ 43 return [[_name copy]autorelease];//稍后对象引用的计数器自动减1 44 } 45 //getter方法内部实现 46 -(Phone *)phone{ 47 return [[_phone retain]autorelease]; 48 } 49 //语义属性为 copy 的对象的 setter 方法的内部实现 50 -(void)setName:(NSString *)name{ 51 if (_name!= name) { 52 [_name release];//立即让该对象的引用计数器减1 53 _name = [[name copy]autorelease]; 54 } 55 } 56 //注意我们已经吧内存机制设定为手动管理模式 57 @synthesize phone = _phone; 58 //语义的对属性为 retain 的对象的 setter 方法的内部实现 59 - (void)setPhone:(Phone *)phone{ 60 if (_phone) { 61 [_phone release]; 62 _phone = [[phone copy]autorelease]; 63 } 64 } 65 @end
1 // 2 // GrilFrinend.h 3 // Property 4 9 #import "Person.h" 10 @class Phone; 11 12 @interface GrilFrinend : Person 13 @property(nonatomic,copy)NSString * address; 14 @property(nonatomic,assign)CGFloat height; 15 @property(nonatomic,retain)Phone *phone; 16 17 - (id)initWithBrand:(NSString *)brand; 18 @end
1 // 2 // GrilFrinend.m 3 // Property 4 9 #import "GrilFrinend.h" 10 #import "Phone.h" 11 12 @implementation GrilFrinend 13 @synthesize name = _ns; 14 //属性的实现 name = _name 的含义:属性name 的setter 和 getter 方法在操作_name实例变量的时候,等号的右边可以随意写,但是系统的机制会先检查,.h中有没有对应的名称的实例变量,如果没有就自动生成一个,生成的默认是一个私有的实例变量 15 //在IOS6.0之后属性可以不写,编译器会自动生成对应方法的实现,操作的实例变量是跟属性同名的 _属性名 的实例变量 16 - (id)initWithBrand:(NSString *)brand{ 17 self = [self initWithName:@"晓红" gender:@"女" age:24]; 18 if (self) { 19 _ns = @"张晓红"; 20 } 21 return self; 22 } 23 24 @end
1 // 2 // Phone.h 3 // Property 4 // 9 #import <Foundation/Foundation.h> 10 11 @interface Phone : NSObject 12 @property(nonatomic,copy)NSString *brand;//品牌 13 - (id)initWithBrand:(NSString *)brand;//品牌初始化 14 @end
1 // 2 // Phone.m 3 // Property 4 // 9 #import "Phone.h" 10 11 @implementation Phone 12 - (id)initWithBrand:(NSString *)brand{ 13 self = [self init]; 14 if (self) { 15 self.brand = brand; 16 } 17 return self; 18 }//品牌初始化 19 @end
代码:
1 // 2 // main.m 3 // Even 4 9 #import <Foundation/Foundation.h> 10 #import "Person.h" 11 #import "Student.h" 12 13 int main(int argc, const char * argv[]) { 14 @autoreleasepool { 15 // insert code here... 16 NSLog(@"Hello, World!"); 17 Person * per = [[Person alloc]initWithName:@"牛建伟" gender:@"男" age:23 address:@"南阳市镇平人"]; 18 NSLog(@"1111+++++%@",per); 19 Student * stu = [[Student alloc]initWithName:@"牛行建" gender:@"男" age:23 address:@"南阳西峡" stunum:@"201207082437" school:@"中原工学院"]; 20 NSLog(@"%@",stu.name); 21 NSLog(@"name = %@ gender = %@ age= %ld address = %@ stunumber = %@ school = %@",stu.name,stu.gender,stu.age,stu.address,stu.stunum,stu.school); 22 NSLog(@"%@",stu); 23 } 24 return 0; 25 }
1 // 2 // Person.h 3 // Even 4 // 5 9 #import <Foundation/Foundation.h> 10 11 @interface Person : NSObject 12 13 @property(nonatomic,copy,readwrite)NSString *name; 14 @property(nonatomic,copy,readwrite)NSString *gender; 15 @property(nonatomic,assign,readwrite)NSInteger age; 16 @property(nonatomic,copy,readwrite)NSString *address; 17 //初始化 18 - (id)initWithName:(NSString *)name 19 gender:(NSString *)gender 20 age:(NSInteger)age 21 address:(NSString *)address; 22 //便利构造器 23 + (Person *)initWithName:(NSString *)name 24 gender:(NSString *)gender 25 age:(NSInteger)age 26 address:(NSString *)address; 27 -(NSString *)description; 28 @end
1 // 2 // Person.m 3 // Even 4 9 #import "Person.h" 10 11 @implementation Person 12 @synthesize name = _namename; 13 @synthesize gender = _gendergender; 14 @synthesize age = _ageagea; 15 @synthesize address = _addressadress; 16 17 //初始化 18 - (id)initWithName:(NSString *)name 19 gender:(NSString *)gender 20 age:(NSInteger)age 21 address:(NSString *)address{ 22 self = [self init]; 23 if (self) { 24 NSString * strr = @"蓝欧学员:"; 25 self.name = name; 26 self.name = [strr stringByAppendingString:name]; 27 self.gender = gender; 28 self.age = age; 29 NSString * str = @"中国华人民共和国河南省"; 30 self.address = address; 31 self.address = [str stringByAppendingString:address]; 32 } 33 return self; 34 } 35 //重写setter getter 36 -(void)setName:(NSString *)name{ 37 if (_namename != name) { 38 [_gendergender release]; 39 NSLog(@"重写setter getter方法"); 40 _namename = [[name retain]autorelease]; 41 } 42 } 43 -(NSString *)name{ 44 return [[_namename retain]autorelease]; 45 } 46 -(void)setGender:(NSString *)gender{ 47 if (_gendergender != gender) { 48 [_gendergender release]; 49 _gendergender = [[gender retain]autorelease]; 50 } 51 } 52 -(NSString *)gender{ 53 return [[_gendergender retain]autorelease]; 54 } 55 -(void)setAddress:(NSString *)address{ 56 if (_addressadress != address) { 57 [_addressadress release]; 58 _addressadress = [[address retain]autorelease]; 59 } 60 } 61 -(NSString *)address{ 62 return [[_addressadress retain]autorelease]; 63 } 64 //便利构造器 65 + (Person *)initWithName:(NSString *)name 66 gender:(NSString *)gender 67 age:(NSInteger)age 68 address:(NSString *)address{ 69 Person * per = [[Person alloc]initWithName:name gender:gender age:age address:address]; 70 return per; 71 } 72 -(NSString *)description{ 73 return [NSString stringWithFormat:@"name = %@ ",self.name];//可以这样写 74 // return [NSString stringWithFormat:@"name = %@ gender = %@ age= %ld adress= %@",_namename,_gendergender,_ageagea,_addressadress]; 75 } 76 @end
1 // 2 // Student.h 3 // Even 4 8 9 #import "Person.h" 10 11 @interface Student : Person 12 13 @property(nonatomic,copy,readonly)NSString * school; 14 @property (nonatomic,retain,readwrite)NSString * stunum; 15 //初始化 16 -(id)initWithName:(NSString *)name 17 gender:(NSString *)gender 18 age:(NSInteger)age 19 address:(NSString *)address 20 stunum:(NSString *)stunum 21 school:(NSString *)school; 22 //便利构造器 23 +(Student *)studentWithName:(NSString *)name 24 gender:(NSString *)gender 25 age:(NSInteger)age 26 address:(NSString *)address 27 stunum:(NSString *)stunum 28 school:(NSString *)school; 29 -(NSString *)description; 30 @end
1 // 2 // Student.m 3 // Even 4 8 9 #import "Student.h" 10 11 @implementation Student 12 @synthesize school = _school; 13 @synthesize stunum = _stunum; 14 //自己设置setter getter 方法 15 -(void)setSchool:(NSString *)school{ 16 if (_school != school) { 17 [_school release]; 18 _school = [[school retain]autorelease]; 19 } 20 } 21 -(NSString *)school{ 22 return [[_school retain]autorelease]; 23 } 24 //初始化 25 -(id)initWithName:(NSString *)name 26 gender:(NSString *)gender 27 age:(NSInteger)age 28 address:(NSString *)address 29 stunum:(NSString *)stunum 30 school:(NSString *)school{ 31 self = [self init]; 32 if (self) { 33 self.name = name; 34 NSLog(@"%@",name); 35 self.gender = gender; 36 self.age = age; 37 self.address = address; 38 self.stunum = stunum; 39 self.school = school; 40 } 41 return self; 42 } 43 //便利构造器 44 +(Student *)studentWithName:(NSString *)name 45 gender:(NSString *)gender 46 age:(NSInteger)age 47 address:(NSString *)address 48 stunum:(NSString *)stunum 49 school:(NSString *)school{ 50 Student * stu = [[Student alloc]initWithName:name gender:gender age:age address:address stunum:stunum school:school]; 51 return stu; 52 } 53 -(NSString *)description{ 54 // NSString * name = self.name; 55 return [NSString stringWithFormat:@"%@",self.name]; 56 // return [NSString stringWithString:@"name = %@ gender = %@ age= %ld address = %@ stunumber = %@ school = %@",name,stu.gender,stu.age,stu.address,stu.stunum,stu.school]; 57 } 58 @end
首先概念:setter和getter方法。
在OC中,为单一的实例变量赋值的方法称为setter方法,读取实例变量的值得方法称为getter方法。
如:NSInteger _age;
OC中setter方法是这样规定的:
声明部分:
-(void)setter:(NSInteger)age; //setter方法 (注意: set +实例变量名( 首字母 大写),忽略下划线)。
-(NSInteger)age;//getter方法(注意:返回值类型与变量类型 致, 法与实例变量名相同,忽略下划线)。
下面是两种方法的实现部分:
-(void)setter:(NSInteger)age
{
_age = age;
}
-(NSInteger)age
{
return _age;
}
由上面方法可以看出,一旦一个项目工程中有多个实例变量参与,那将会引入多个settergetter方法的编写,导致代码繁琐,影响开发周期,为此OC2.0开始出现了属性的点语法操作,这样一来大大简化了程序员的开发难度。
下面看看属性的点语法(又称语法糖):
- 属性的特性
readonly:只读状态,是告诉编译器,属性只成getter方法。
readwrite:读写状态,是告诉编译器属性即生成setter又生成getter方法。
- 原子性:
- 原子性控制(nonatomic, atomic)
atomic:原子特性,settergetter方法在多线程访问下是绝对安全的,即settergetter内部做了多线程访问的处理。默认的原子特性。
nonatomic:非原子性。settergetter方法内部都不会做多线程访问处理,仅仅是普通的settergetter方法。
- 原子性的控制使用:
程序开发的过程中,setter、getter会频繁使用,如果使用atomic需要不断对settergetter加锁解锁以保证多线程的安全性访问,但是这样会占用很多系统资源,降低系统的性能,(多线程的使用之后我会详细讲解)
声明属性时,通常使用nonatomic,某些属性需要多线程的安全时候,才会去定义为atomic。
例如:@property(nonatomic)NSString* name;
- 语义设置(assign retaincopy)
如果属性是非对象类型(普通类型如int float double array,枚举),属性的语义设置使用assign.
如果属性是对象类型的,属性的语义设置为retain。
如果属性是对象类型并且想得到对象的副本,使用copy(对于retain和copy的区别内存管理会讲解很透彻滴)。
如果语义设置关键字是assign:
@property(nonatomic, assign)NSInteger age;
- setter方法的内部实现:
-(void)setAge:(NSInteger)age
{
_age = age;
}
- getter内部实现:
-(NSInteger)age
{
return _age;
}
如果语义设置是retain,@property(nonatomic, retain)NSString* name;
setter方法内部实现是这样的:
-(void)setName:(NSString*)name
{
if(_name != name)
{
[_name release];
_name = [name retain];
}
}
getter内部方法实现如下:
-(NSString*)name
{
return [ [_name retain] autorelease ];
}
- setter的内部实现
}
}
- getter内部实现:
-(NSString*)gender
{
return [ [ _gender retain] autorelease];
}
- 点语法
定义:点语法是OC2.0中定义的语法格式,提供了一种便捷的属性访问方式。
点语法的使用:只要符合系统默认的setter getter书写格式的方法都可以使用点语法。
例如实例变量 _name
- setter方法
[person setName:@"Rephontil"];
使用点语法替换为: person.name = @"Rephontil";
- getter方法:
NSString* string = [person name];
使用点语法的写法: NSString* string = person.name;
属性是一对setter getter方法,点语法是属性的另一种调用格式。