属性是Objective-C 2.0定义的语法,为实例变量提供了setter和getter方法的默认实现。能在一定程度上简化程序代码,并且增强实例变量的访问安全性。
// main.m
#import<Foundation/Foundation.h>
#import "Person.h"
#import "Teacher.h"
#import "Student.h"
#import "Phone.h"
int main(intargc, const char * argv[]) {
@autoreleasepool {
// //属性
// Person *person = [[Person alloc] init];
//
// // 属性的使用语法
// // [消息的接受者方法名];
// // 对象名.属性名 (点语法)
// [person setGender:@"男"];
// person.gender = @"女";
// NSLog(@"%@ %@",person.gender,[person gender]);
//
// Teacher *teacher = [Teacher TeacherWithName:@"name"gender:@"gender" age:22];
// [teachersayHi];
//
// Student *stu = [[Student alloc]init];
// // 因为属性声明为readonly,因此不能赋值,但是可以取值。
// //stu.name = @"tz";
// NSLog(@"%@",stu.name);
// stu.gender = @"女";
// NSLog(@"%@",stu.gender);
//
// stu.age = 2222;
// stu.gender = @"w";
// stu.score = @"888";
// KVC(key-value-coding)
// 间接的为实例变量赋值取值
//
Phone *p = [[Phone alloc]init];
p.color = @"yellow";
NSLog(@"%@",p.color);
// key值是@"实例变量名",实例变量可以带或者不带下划线,因为方法内部做了优化,没有下划线自动加下划线,。
[psetValue:@"red" forKey:@"colors"];
NSLog(@"%@",[pvalueForKey:@"_color"]);
// 将A类的对象a作为B类的实例变量,如果想通过kvc(键值路径)给a的实例变量赋值,那么需要先通过kvc给a对象赋值。
Student *stu1 = [[Student alloc]init];
// 通过kvc为 p 的实例变量stu赋值
[p setValue:stu1 forKey:@"stu"];
// 通过kvc为p的实例变量stu的name赋值
[psetValue:@"zrt" forKeyPath:@"stu.name"];
//通过路径赋值
NSString *s = [pvalueForKeyPath:@"stu.name"];
// 打印
NSLog(@"%@ %@",s,p.stu.name);
// 3 - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString*,id> *)keyedValues
// 通过字面量创建一个字典对象
NSDictionary *dic =@{@"color":@"brand",@"brand":@"兰博基尼",@"stu":stu1};
// 通过kvc整体为类的实例变量赋值
Phone *p1 = [[Phone alloc]init];
[p1setValuesForKeysWithDictionary:dic];
NSLog(@"%@ %@%@",p1.color,p1.brand,p1.stu);
// ARC 属性修饰词:assign,weak,strong,copy;
// assign 修饰费对象类型
// weak 修饰代理
// strong 相当于 MRC中的retain
// copy 相当于 MRC 中的copy
}
return 0;
}
//Person.h
#import<Foundation/Foundation.h>
@interface Person : NSObject
{
NSString *_name;
}
@property(nonatomic,retain) NSString*gender;
// 等同于下面两句话
//- (void)setGender:(NSString *)gender;
//- (NSString *)gender;
@property(nonatomic,assign) NSInteger age;
// 属性
// 1、属性的本质是setter,getter方法,它的作用是为实例变量赋值、取值。
// 2、属性名前面的数据类型决定了 setter方法的参数类型,getter 方法的返回值类型
// 3、属性名决定了方法名
// setter 和 getter 本质上是为实例变量赋值。
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
// Person.m
#import "Person.h"
@implementation Person
// 若完全不写 @synthesize,默认生成_gender(带有下划线) 的实例变量名
//// 如果 @synthesize 属性名:不写 = 实例变量名,默认生成的实例变量名和属性名一样。
//@synthesize gender;
//- (instancetype)init{
// gender = @"123";
// return self;
//}
// 等号右边的实例变量称为当前类的私有实例变量,不能被子类以及外界访问。
//@synthesize gender = _address;
// //如果需要重写 setter 和 getter 方法,必须加上@synthesize属性名 = 实例变量名
//// xcode4.5 之后,系统默认实现了setter 和 getter 方法
@synthesize gender = _gender,age = _age;
- (void)setGender:(NSString *)gender{
_gender = gender;
}
- (NSString *)gender{
return _gender;
}
- (void)setAge:(NSInteger)age{
_age = age;
}
- (NSInteger)age{
return _age;
}
- (void)setName:(NSString *)name{
_name = name;
}
- (NSString *)name{
return _name;
}
@end
//属性的属性
// 1 读写性控制readonly,readWrite
//如果属性声明为readonlyname只生成 getter 方法。
// 如果属性的读写性控制不写,默认为readwrite。
@property(readonly)NSString *name;
// 2、原子性控制,包含atomic(原子性控制),nonatomic(非原子性控制)。
//atomic 主要运用在线程安全这一块,一般我们用nonatomic,因为atomic会不断的加线程锁,降低处理效率
// 默认为atomic,一般我们用nonatomic。
@property(nonatomic)NSString *sex;
// 3、语义设置,包含assign,retain,copy
// 一般非对象类型我们用assign修饰
// 对象类型用retain,copy修饰,且需要复制的情况,我们才用到copy,一般我们使用retain
// 默认为assign
// 代理用 assign,防止循环引用
// block 用 copy,因为 block 在栈区,防止使用后释放,所以用 copy,拷贝一份到堆区,自己释放。
//Student.m
#import "Student.h"
@implementation Student
@synthesize gender = _gender,score =_score,age = _age;
// 重写属性的实现
// 语义设置为assign
- (void)setAge:(NSInteger)age{
_age = age;
}
- (NSInteger)age{
return _age;
}
// 2、语义设置为retain
- (void)setGender:(NSString *)gender{
if (_gender != gender) {
[_gender release];
_gender = [gender retain];
}
}
- (NSString *)gender{
return [[_gender retain]autorelease];
}
// 3、语义设置为copy
- (void)setScore:(NSString *)score{
if (_score != score) {
[_score release];
_score = [score copy];
}
}
- (NSString *)score{
return [[_score retain]autorelease];
}
@synthesize school = _school;
- (void)setSchool:(NSString *)school{
if (_school != school) {
[_school release];
_school = [school retain] ;
}
}
- (NSString *)school{
return [[_school retain] autorelease];
}
- (instancetype)initWithName:(NSString*)name gender:(NSString *)gender age:(NSInteger)age{
if (self = [super init]) {
_name = name;
_gender = gender;
_age = age;
}
return self;
}
+ (Student *)studentWithName:(NSString*)name gender:(NSString *)gender age:(NSInteger)age{
Student *student = [[Student alloc]init];
return student;
}
- (void)sayHi{
NSLog(@"%@ %@%ld",_name,_gender,_age);
}
@end
// Phone.m
#import "Phone.h"
@implementation Phone
// 当设置实例变量的值的时候,无此key值,则执行这个方法。空实现就不会崩溃。
- (void)setValue:(id)valueforUndefinedKey:(NSString *)key{
if ([key hasPrefix:@"colors"]) {
[selfsetValue:@"red" forKey:@"color"];
}
}
// 当取值的时候,无此key值,会执行这个方法
- (id)valueForUndefinedKey:(NSString *)key{
NSLog(@"无此key");
return 0;
}
@end