您的位置:首页 > 移动开发 > Objective-C

iOS之《Effective Objective-C 2.0》读书笔记(6)

2017-08-18 11:36 489 查看

第六条:理解“属性”这一概念

1.@property

(1)编译器遇到关键字@property会自动为这个属性添加setter/getter方法,避免了每次手动添加的麻烦。

(2)编译器就会为我们自动生成对应的实例变量_myTitle:

@property (copy, nonatomic) NSString *myTitle;//声明属性


2.使用@property时相关的关键字

(1)atomic 和 nonatomic

(1)atomic:表示对对象的操作属于原子操作,支持多线程,使用atomic比nonatomic更耗费系统资源。
(2)nonatomic 表示访问器的访问不是原子操作,不支持多线程访问安全,但是访问性能高。
(3)原因:在多线程的下对对象的访问都需要先上锁访问后再解锁,保证不会同时有几个操作针对同一个对象,所以多线程访问的情况下,会耗费资源,降低性能


(2)retain,assign和copy

(1)assign:只可以对基本数据类型(如CGFloat,NSInteger,Bool,int,代理对象)等使用。该方式会对对象直接赋值而不会进行retain操作
(2)retain :使对象的应用计数增加一
(3)copy :表示重新建立一个新的计数为1的对象,然后释放掉旧的值

(4)原因:retain是对指针的拷贝,copy是对内容的拷贝
比如:NSString 对象的地址为0x100,其内容为“string”,如果使用copy到另外一个NSString对象,则会生成另外一个地址为0x110的对象,只不过内容仍然是‘string“。如果使用retain到另外一个NSString对象,则该对象的地址仍然为0x100,只不过该对象的计数变为2.


(3)strong 和 weak

(1)strong 强引用,strong修饰的属性一般不会自动释放。默认的所有实例变量和局部变量都是strong指针。
eg1: @property (nonatomic, strong) NSArray *dataList;
@property (nonatomic, strong) UILabel *label;
eg2: 使用懒加载定义控件的时候,一般也用strong
eg3:addSubView 默认对其 subView 进行了强引用

(2)weak 弱引用,主要用于防止循环引用
eg1: 使用 sb 或者 xib 给控件拖线的时候: @property (weak, nonatomic) IBOutlet UILabel *label;
eg2: delegate模式,你的ViewController通过strong指针(self.view)拥有一个UITableView, UITableView的dataSource和delegate都是weak指针,指向你的ViewController。


3.@synthesize

(1)@synthesize的使用有很悠久的历史了,此处不研究,只是说明@synthesize现在的具体应用

(2)@synthesize的作用:就是让student = ?中的后者这个变量来“代替”属性,从而可以通过操作变量来进行属性的操作

// 在 .h文件
@property (copy, nonatomic) NSString *student;
// 在.m文件
@synthesize   student  =  student //可以直接使用student,而非self.student
// 默认情况下:
@synthesize   student  =  _student  //使用self.student


(3)两者的区别:

a:添加:@synthesize   student  =  student:属性本身的引用计数是不会增加的,因为没有经过调用setter方法或者是getter方法
b:使用self.student这种操作方式的话,实质上是通过setter或者是getter方法进行操作,引用计数会随着不同的操作而改变


4.@dynamic:(参考

(1)@dynamic的作用:禁止编译器为@property产生setter和getter方法

// .h文件
@property(nonatomic,copy)NSString *name;
// .m文件
@dynamic name;
// 赋值
name = @"zhangsan";   // 报错:Use of undeclared identifier "name"


(2)两种办法手动实现setter和getter方法:

,,,,,,,,,,方法一:自己提供setter和getter方法,将编译器自动生成的setter和getter方法手动再写一遍

1》需要在类中显式提供实例变量,因为@dynamic不能像@synthesize那样向实现文件(.m)提供实例变量
// .h文件
{
NSString *_name;
}
@property(nonatomic,copy)NSString *name;

2》手动写setter和getter方法
// .m文件
@dynamic name;
- (void) setName:(NSString *)name
{
if (_name != name) {
_name = [name copy];
}
}
- (NSString *) name
{
return _name;
}


………方法二:在运行时决定setter和getter对应实现的C函数,使用了NSObject提供的resolveInstanceMethod:方法:

1》需要显式声明实例变量而且访问级别是@public,为了隐藏该实例变量,将声明放在扩展(extension)中
// .h文件
@property(nonatomic,copy)NSString *name;

2》手动写setter和getter方法
// .m文件
{
@public
NSString *_name;
}
@dynamic name;
+ (BOOL) resolveInstanceMethod:(SEL)sel
{
// Capture setName: and name method
if (sel == @selector(setName:)) {
class_addMethod([self class], sel, (IMP)setName, "v@:@");
return YES;
}
else if (sel == @selector(name)) {
class_addMethod([self class], sel, (IMP)getName, "@@:");
return YES;
}

return [super resolveInstanceMethod:sel];
}


5.set,get 方法

(1)set,get方法的书写

// s
ac45
et方法的书写:
-(void)setAge:(int)age
{
self.age = age;//不能这样写,因为赋值号左边的self.age实际上是 [self setAge:age]的简写,会调用set方法
_age = age;//要这样写
}
// get方法的书写:
-(int)age
{
return _age;
}


(2)set,get方法的使用:set是给属性赋值的,get是取得属性值的,不一定同时存在。

// set方法的使用
[student setAge:12];
// get方法的使用
NSLog(@"%@",[student age]);


(3)定义属性时需要注意的:

@property (nonatomic, strong) NSString *age;//这个就是会自动生成get、set方法,()里省略了readwrite
@property (nonatomic, strong, readonly) NSString *age;//这个就是只有get方法,不能set
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息