属性(Property)
封装一个学生类,
实例变量: name, age
自定义初始化方法
便利构造器
setter, getter
重写description方法
Student.h #import <Foundation/Foundation.h> @interface Student : NSObject { NSString *_name; NSInteger _age; NSString *_gender; } //属性的声明 @property NSString *gender; - (void)setName:(NSString *)name; - (NSString *)name; - (void)setAge:(NSInteger)age; - (NSInteger)age; - (instancetype)initWithName:(NSString *)name age:(NSInteger)age; + (instancetype)studentWithName:(NSString *)name age:(NSInteger)age; - (void)show; @end
Student.m #import "Student.h" @implementation Student //属性的实现 @synthesize gender; - (void)setName:(NSString *)name { _name = name; } - (NSString *)name { return _name; } - (void)setAge:(NSInteger)age { _age = age; } - (NSInteger)age { return _age; } - (instancetype)initWithName:(NSString *)name age:(NSInteger)age { self = [super self]; if (self) { _name = name; _age = age; } return self; } + (instancetype)studentWithName:(NSString *)name age:(NSInteger)age { // Student *stu = [[Student alloc] init]; // [stu setName:name]; // [stu setAge:age]; return [[Student alloc] initWithName:name age:age]; } - (void)show { NSLog(@"name:%@, age:%ld", _name, _age); } - (NSString *)description { return [NSString stringWithFormat:@"name:%@, age:%ld", _name, _age]; } @end
main.m Student *student = [[Student alloc] initWithName:@"小花" age:18]; NSLog(@"%@", student); //使用自定义的类生成的对象, 打印结果<类名: 地址> //打印对象的实例变量 NSLog(@"name:%@, age:%ld", [student name], [student age]); //封装方法, 快速打印实例变量 [student show];
%@打印的实质: 打印度是这个对象调用description方法返回的字符串
description是NSObject中的方法
NSLog(@"%@", student); NSLog(@"%@", [student description]);
点语法 Student *stu = [[Student alloc] init]; NSLog(@"%@", stu); 通过setter为变量赋值 [stu setName:@"李思思"]; [stu setAge:28]; 通过getter取实例变量的值 NSLog(@"%@, %ld", [stu name], [stu age]);
点语法的作用: 快速调用setter和getter
点语法的前提: 必须要有setter和getter
注: 点语法出现在=号的左侧, 调用setter, 其他位置调用getter
stu.name = @"小哇"; stu.age = 28; NSLog(@"%@, %ld", stu.name, stu.age);
属性: 快速生成setter和getter方法
属性声明
格式: @property数据类型实例变量名;
属性实现
格式:
@synthesize实例变量名;
stu.gender = @"女"; NSLog(@"%@", stu.gender);
定义一个手机类
实例变量: 品牌, 价格, 颜色
属性
重写description
Phone.h #import <Foundation/Foundation.h> @interface Phone : NSObject { // NSString *_brand; // CGFloat _price; // NSString *_color; } @property NSString *brand, *color; @property CGFloat price; @end
Phone.m #import "Phone.h" @implementation Phone //@synthesize brand, price, color; //如果不写属性的实现, 默认系统补上的形式 //@synthesize brand = _brand, price = _price, color = _color; //@synthesize brand; //1.自动生成一个实例变量brand; //2.setter方法和getter方法对实例变量brand进行操作 //@synthesize brand = _brand; //1.自动生成一个实例变量_brand; //2.setter方法和getter方法对实例变量_brand进行操作 - (NSString *)description { return [NSString stringWithFormat:@"brand:%@ price:%.2f color:%@", _brand, _price, _color]; } @end
main.m Phone *phone = [[Phone alloc] init]; phone.brand = @"iPhone 6s"; phone.price = 1998; phone.color = @"土豪金"; NSLog(@"%@", phone);
属性的优化
1.属性声明的优化, 如果数据类型相同, 可以写在一行, 用逗号隔开
注: 对象要加*
2,属性实现的优化: 多个属性实现可以写在一行, 用逗号隔开
3.属性的实现部分是可以省略的, 系统自动补上属性的实现部分
4.实例变量可以省略, 属性会自动补上实例变量
封装一个猫类
实例: 姓名, 品种, 年龄, 颜色
Cat.h #import <Foundation/Foundation.h> @interface Cat : NSObject @property (nonatomic, retain) NSString *name, *type, *color; @property (nonatomic)NSInteger age; //苹果的习惯: 如果属性是BOOL类型, 一般会修改getter方法的名字, 改成"is+实例变量" @property (nonatomic, getter=isSame) BOOL same; @end
Cat.m #import "Cat.h" @implementation Cat - (NSString *)description { return [NSString stringWithFormat:@"name:%@ type:%@ age:%ld color:%@", _name, _type, _age, _color]; } @end
属性的修饰词
作用: 管理和控制setter和getter
1.多线程组
a. atomic: 原子性, 同一时刻只能执行一种操作(getter或setter), 安全性高, 执行效率比较低, 一般用于多线程, 默认值
b. nonatomic: 非原子性的, 同一时刻能执行多种操作(getter或setter), 执行效率高
注: 一般优先写nonatomic, 多线程下为了安全起见, 才写atomic
2.内存管理组
a. assign: 基本数据类型(int, char, float, double, long, short, BOOL, NSInteger, CGFloat), 默认值
b. retain: 对象
c. copy: 对象, 必须遵守<NSCopying>协议
3.读写组
a. readwrite: 读写, 会生成setter和getter, 默认值
b. readonly: 只读, 只生成getter
4.方法重命名组
a. setter=名字
b. getter=名字
KVC: key-value coding, 键值编码, 提供了一种间接访问属性的方式
Game.h #import <Foundation/Foundation.h> @interface Game : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic) CGFloat time; @property (nonatomic) NSInteger count; @end
Game.m #import "Game.h" @implementation Game - (NSString *)description { return [NSString stringWithFormat:@"name:%@ time:%.2f count:%ld", _name, _time, _count]; } @end
main.m //setter [game setName:@"双升"]; NSLog(@"%@", [game name]); //点语法 game.name = @"斗地主"; NSLog(@"%@", game.name); //间接访问(KVC) [game setValue:@"接竹竿" forKey:@"name"]; NSLog(@"%@", [game valueForKey:@"name"]); //注: key内填写属性名
KVC检索的过程
1.getter, setter
2.实例变量_<key>, <key>
3.setValue:forUndefinedKey:, valueForUndefinedKey
Boy.h #import <Foundation/Foundation.h> //在外部访问实例变量, 有哪些途径 //1. @public, 通过->访问 //2. setter, getter //3. KVC @interface Boy : NSObject { NSString *_name; NSInteger _number; } @end
Boy.m #import "Boy.h" @implementation Boy - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"value:%@ key:%@", value, key); } - (id)valueForUndefinedKey:(NSString *)key { return nil; } @end
main.m Boy *boy = [[Boy alloc] init]; [boy setValue:@"李磊" forKey:@"name"]; NSLog(@"%@", [boy valueForKey:@"name"]); [boy setValue:@"18" forKey:@"age"]; NSLog(@"%@", [boy valueForKey:@"age"]); [boy setValue:@15 forKey:@"number"]; NSLog(@"%@", [boy valueForKey:@"number"]); Boy *boy1 = [[Boy alloc] init]; [boy1 setValuesForKeysWithDictionary:@{@"name": @"韩梅梅", @"number": @19}]; NSLog(@"%@ %@", [boy1 valueForKey:@"name"], [boy1 valueForKey:@"number"]);
属性中出现的问题
Girl.h #import <Foundation/Foundation.h> @interface Girl : NSObject @property (nonatomic) NSInteger age; @end
Girl.m #import "Girl.h" @implementation Girl //当同时重写了setter和getter方法后, @synthesize age = _age;就失效了 //解决方案: 自己补上@synthesize age = _age; @synthesize age = _age; //当属性生成的setter方法不满足需求时, 可以重写setter方法 - (void)setAge:(NSInteger)age { if (age > _age) { _age = age; } } //当属性生成的getter方法不满足需求时, 可以重写setter方法 - (NSInteger)age { return _age - 2; } @end
main.m Girl *girl = [[Girl alloc] init]; girl.age = 17; NSLog(@"%ld", girl.age); //每次赋值的年龄都大于上一次 girl.age = 10; NSLog(@"%ld", girl.age);