1、属性:帮你自动生成setter 和 getter 方法
属性的声明:(写在.h中)
格式: @property 数据类型 属性名
属性的实现:(写在.m中)
格式: @synthesize 属性名:
例子1:
Person.h
@interface Person : NSObject
//属性的声明:属性:属性名就是实例变量名去掉下划线
@property NSString *gender;
@end
Person.m
//属性的实现
@synthesize gender;
@end
main.m
//属性方法实现gender的setter和getter方法
person.gender = @"妖";
NSLog(@"%@",person.gender);//点语法
NSLog(@"%@",[person gender]);//setter、getter方法
例子2:
teach.h
@interface Teacher : NSObject
//输入属性的类型相同的话,此时就可以把它们写在一个属性声明中,但是每一个属性名前要加*,(是基本数据类型的就不用加*)
@property NSString *name,*color;
@property NSInteger age;
@property CGFloat score;
@end
teach.m
//属性的实现部分可以写在一起,用逗号隔开
//@synthesize name,color,age,score;
//自Xcode5.0之后属性实现部分不应写了,极大提高了变成速率
//如果不写了,系统默认帮你生成以下语句,自动创建一个_name实例变量,并且自动生成setter 和getter方法
//如果实例变量不写
//@synthesize name = _name;
- (NSString *)description
{ +++++++++description 中不能打印self+++++++++++
// return [NSString stringWithFormat:@"%@-%ld-%.2lf-%@-%@", _name,_age,_score,_color,self]; (1)ERROR!!!
return [NSString stringWithFormat:@"%@-%ld-%.2lf-%@", _name,_age,_score,self.color];//这样是可以的
}
属性的优化:
1.属性的声明和实现可以合并
2.实现可以省略实例变量的声明(系统自动帮你生成属性名 加下划线的实例变量 如:_name)
3.属性的实现可以省略
main.m
//定义一个Teacher类,实例变量name age score color
//定义一个Teacher对象
Teacher *tea = [[Teacher alloc]init];
tea.name = @"小仓";
tea.age = 18;
tea.score = 85.3;
tea.color = @"纯白种人";
NSLog(@"%@-%ld-%.2lf-%@",tea.name,tea.age,tea.score,tea.color);
NSLog(@"%@",tea);
======================================================
2、属性的属性:属性的修饰符 主要用来控制setter 和 getter 的方法的实现细节
1.访问控制组 atomic:原子性,修饰的属性同一时刻只能使用setter 或getter,(setter和getter 是互斥的),安全但效率低;
atomic 使用场景:在多线程下为保护数据安全可以使用atomic
nonatomic :非原子性,允许同时使用setter 或getter方法,不安全但效率高,推荐使用nonatomic
2.内存管理组
assign 默认值 基本数据类型使用assign修饰,代理属性使用assign修饰
retain 对象类型一般使用retain
copy 字符串一般用copy修饰,如果要使用copy修饰属性,这个属性必须遵循NSCoping协议
3.读写控制组
readWrite : 可读可写,自动帮你生成setter 和getter 方法 默认值
readOnly :只读,系统只帮你生成getter方法
4.重命名组
setter = setter新名字
getter = getter 新名字
(除了BOOL特殊情况,其他的一般不使用这种方法)
例子1:定义一个Boy的类;实例变量 name age gender
自定义初始化方法
遍历构造器方法
重写description 方法
Boy.h
@interface Boy : NSObject
//属性修饰符写在@propety后面的()小括号中
//属性修饰符可以写多个,每一个修饰符之间用逗号隔开
//系统默认readwrite ,平时可以不写
@property (nonatomic,copy,readwrite,setter=setAAA:,getter=AAA)NSString *name;
@property (atomic,copy,readwrite)NSString *gender;
@property (nonatomic,assign,readonly)NSInteger age;
//苹果的习惯,如果一个属性是Bool类型的,会对getter方法重命名
@property (nonatomic,assign,readwrite,getter=isFalg)BOOL flag;
@end
Boy.m 使用属性可以不写实现部分
main.m
//建一个Boy对象
Boy *boy = [Boy boyWithName:@"zhangsan" gender:@"yao" age:18];
NSLog(@"%@",boy);
// readOnly 只读不能写
// boy.age = 18; error!!
NSLog(@"%ld",boy.age);
//name属性的setter和getter方法起了别名
[boy setAAA:@"Lisi"];
NSLog(@"%@",[boy AAA]);
boy.name = @"Wanger";
NSLog(@"%@",boy.AAA);
boy.name = @"Mazi";
NSLog(@"%@",boy.name);
例子2: 定义一个Girl类,实例变量 name,sex,age,height,写属性的属性,自定义初始化方法,便利构造器方法,重写description方法
Girl.h
@interface Girl : NSObject
@property (nonatomic,copy)NSString *name;
@property(nonatomic,copy) NSString *sex;
@property (nonatomic,assign)NSInteger age;
@property (nonatomic,assign)CGFloat height;
//- (void)sayHi; error!!!
- (id)initWithGirlFriend : (NSString *)name sex : (NSString *)sex age : (NSInteger)age height : (CGFloat)height;
+ (id)girlWithGirlFriend : (NSString *)name sex : (NSString *)sex age : (NSInteger)age height : (CGFloat)height;
@end
Girl.m
@implementation Girl
//当属性生成的setter和getter方法的实现,不满足你的需求时,可以重写setter和getter方法
//当完全重写setter和getter方法时,@synthesize name= _name;,就是实效的
解决问题的方法
1.只重写setter和getter 方法中的一个
2.自己添加@synthesize name= _name;
@synthesize name= _name;
- (void)setName:(NSString *)name
{
NSLog(@"你好小姐");
// _name = name;
// self.name = name; //self.name == [self setNane : name];
// NSLog(@"%@",self.name); //self.name == [self name];
_name = name;
}
- (NSString *)name{
// return self.name; error!!! [self name]; (2)ERROR!!!
return _name;
}
++++++方法内部是不能用方法调用自己++++++
//- (void)sayHi{
// NSLog(@"小仓");
// [self sayHi];
//} ( 3) ERROR!!!
//初始化和遍历构造器方法
- (id)initWithGirlFriend : (NSString *)name sex : (NSString *)sex age : (NSInteger)age height : (CGFloat)height{
if (self = [super init]) {
_name = name;
_sex = sex;
_age= age;
_height = height;
}
return self;
}
+ (id)girlWithGirlFriend : (NSString *)name sex : (NSString *)sex age : (NSInteger)age height : (CGFloat)height{
return [[Girl alloc]initWithGirlFriend:name sex:sex age:age height:height];
}
//description方法
- (NSString *)description
{
return [NSString stringWithFormat:@"%@-%@-%ld-%.2lf", _name,_sex,_age,_height];
}
--------------------------------------------------------------------
//第3知识点KVC Key-Value-Coding 键值编码 例题中的调用部分
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"没有在Girl类中找到此key值");
}
- (id)valueForUndefinedKey:(NSString *)key{
return nil;
}
@end
main.m
Girl *g = [Girl girlWithGirlFriend:@"如花" sex:@"yao" age:28 height:175.6];
NSLog(@"%@",g);
g.name = @"翠花";
NSLog(@"%@",g.name);
====================================================
3、 KVC Key-Value-Coding 键值编码
通过KVC访问实例变量,是一种间接访问实例变量的形式
例子:
Man.h
@class Girl;
@interface Man : NSObject
{
NSString *_name;
}
@property(nonatomic,retain)Girl *girlFriend;
//@property (nonatomic,copy)NSString *name; //做例子实例变量
@property (nonatomic,assign)NSInteger age;
- (id)initWithName : (Girl *)girlFriend name : (NSString *)name age : (NSInteger)age;
+ (id)manWithName : (Girl *)girlFriend name : (NSString *)name age : (NSInteger)age;
@end
Man.m
#import "Man.h"
#import "Girl.h"
@implementation Man
//实现初始化方法
- (id)initWithName : (Girl *)girlFriend name : (NSString *)name age : (NSInteger)age{
if (self = [super init]) {
_girlFriend = girlFriend;
_age = age;
_name = name;
}
return self;
}
//实现遍历构造器方法
+ (id)manWithName : (Girl *)girlFriend name : (NSString *)name age : (NSInteger)age{
return [[Man alloc]initWithName:girlFriend name:name age:age];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@-%@-%ld", _girlFriend,_name,_age];
}
------------------------------------------------
//防止没有找到对应的key值而引起的Crash
- (void)setValue:(id)value forUndefinedKey:(NSString *)key //容易打错
{
NSLog(@"哈哈,没有找到对应key值");
}
//防止没有找到对应的key值而引起的Crash
- (id)valueForUndefinedKey:(NSString *)key{
return nil;
}
@end
main.m
//通过key值去类中查找实例变量,先判断有没有实例变量name,若没有就赋值,如果没有接着判断有没有_name,如果有酒赋值
Man *man = [[Man alloc]init];
[man setValue:@"妖" forKey:@"name"];
NSLog(@"%@",[man valueForKey:@"name"]);
[man setValue:g forKey:@"girlFriend"];
NSLog(@"%@",[man valueForKey:@"girlFriend"]);
//想通过man这个对象给girl 这对象的名字赋值@"棉花"
[[man valueForKey:@"girlFriend"] setValue:@"棉花" forKey:@"name"];
//通过KVC把棉花打印出来
NSLog(@"%@",[[man valueForKey:@"girlFriend"]valueForKey:@"name"]);
//KVC通过路径赋值取值(即使没有是实现setter 和 getter 方法也可以通过KVC赋值和取值)
[man setValue:@"棉花糖" forKeyPath:@"girlFriend.name"];
NSLog(@"%@",[[man valueForKey:@"girlFriend"]valueForKey:@"name"]);
NSLog(@"%@",[man valueForKeyPath:@"girlFriend.name"]);
总结:注意前三个例题中的ERROR!!!错误造成Crash!原因是造成递归显现!
转自:http://blog.csdn.net/qq_31810357