OC中对实例变量的相关处理方法——属性
在OC中对于类的处理,我们使用了extensionprotocol category等处理方法,间接或者直接实现了对类(协议、延展和代理)和实例变量(继承)的功能扩展。
接下来尝试对实例变量的相关性能进行整理。
(一)实例变量的定义和设置
实例变量的定义及其初始化
实例变量是针对类而言的,实例变量的具体值由对象赋值。定义时候要注意变量类型、变量的可见度、变量下划线(苹果规定)
相关知识点:
初始化方法(注意书写规范)
-(instancetype)initWithName:(NSString*)name age:(NSInteger)age;
-(instancetype)initWithName:(NSString*)name age:(NSInteger)age
{
self=[super init];
if(self){
self.name=name;//也可以写成[self setName:name];
self.age=age;//可以写成[self setAge:age];
}
return self;
}
便利构造器
+ (Student*)studentWithName:(NSString*)nameage:(NSInteger)age;
+ (Student*)studentWithName:(NSString*)nameage:(NSInteger)age
{
return [[Student alloc] initWithName: name age: age];
}
注意:遍历构造器在调用后,需要对其进行空间释放
Student *zhangsan=[Student studentWithName:@”name”age:24];
[zhangsan release];
实例变量的setter
-(void)setName:(NSString*)name;
-(void)setName:(NSString*)name
{
self.name=name;
}
实例变量的getter
-(NSString*)name;
-(NSString*)name
{
}
实例变量的可见度(@public,@protected,@private)
@interface Person:NSObject
{
@public
NSString *_name;
}
@end
对于变量的可见度,可以参考苹果官方对于这个的说明图:
@private修饰的变量只能在自己的类中适用。
@protected修饰的变量不仅能够在自己的类中使用,而且在其子类中适用。
@public在内部外面都可以使用。
(二)实例变量与属性的区别与联系
属性的引入动机:简化代码
属性property就是一组setter和getter
(三)属性的定义和设置
属性的引入格式
正规格式:
@property NSInteger score;//属性的声明
@synthesize score=_score;//属性实现,系统自动生成了一组设置器和访问器
其实在我们定义了属性的声明后,系统已经默认生成了设置器与访问器,并且分别实现了设置器与访问器。一个属性声明相当于一组设置器与访问器。因此以后我们可以省略设置器与访问器的实现文件。
属性定义注意事项:
@property NSString name;//属性的声明对变量的书写格式要注意,正常情况下没有下划线
@synthesizename=_name,age=_age,sex=_sex,course=_course;
//这句实现可以省略了。
@synthesize name,age,sex,course;
//当不写=的时候,系统会认为变量和赋值名相同。相当于生成了一个Extension,又定义了四个私有(private)变量。
(四)对属性本身的修饰:属性的属性(attribute)
(1)可读性属性
readwrite:默认attribute,默认生成了设置器与访问器。
readonly:只读,在@implementation中默认只生成了一个getter,我们可以使用点语法对其进行访问,但是如果对其进行赋值,就会报错。
(2)原子性属性
原子性属性是针对程序的多线程而言的
atomic:非原子属性需要我们声明,意思就是允许多线程操作。
nanatomic:非原子属性需要我们声明,意思就是不允许多线程操作。为了兼顾系统性能,我们一般选择非原子属性来修饰我们的变量。
(3)语义属性
assign:(破旧房子用assign属性直接赋值)是直接赋值方法。对于一般的数据类型,包括C中的基本数据类型都适用。变量的实现方式是直接赋值。OC中的对象假如也使用assign属性可行,但是不安全(系统会提示报警),因为assign对于在引用计数下的对象特性,只创建了一个弱引用(也就是平时说的浅复制)。这样使用变量会很危险。当你release了前一个对象的时候,被赋值的对象指针就成了无头指针了。因此在为对象类型的变量声明属性的时候,尽量少(或者不要)使用assign。
Assign的具体实现方式
@property (readwrite,nanatomic,assign)NSInteger age;
//这里是对age的修饰,age是一个整型变量,可以读写,可进行多线程操作,采用直接赋值方法。
@implemmentation
{
self.age=age;
或者写成
_age=age
}
retain:适用于OC中的对象类型,变量的赋值方式
retain的变量atribute仅仅是针对对象类型来说的。
@property (readwrite,nanatomic,retain)NSString name;
retain的实现机理?
我们用atribute对这个name变量进行了定义,那么系统默认生成了一个setter和getter,如果下面分别是其详细实现方法
setter方法
-(void)setName:(NSString*)name;
-(void)setName:(NSString*)name
{
if(_name!=name){
[_name release];
name=[name retain];
}
}
getter方法
-(NSString*)name;
-(NSString*)name{
return [[_name retain] @autorelease];
}
copy:使用于OC中遵循了<NSCopying>协议的对象类型。
深拷贝:对对象内容的拷贝
mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。
浅拷贝:对象指针的拷贝
注意:对于可变对象为深复制,引用计数不改变;
对于不可变对象是浅复制,引用计数每次加一。始终返回一个不可变对象。
总结:关于assign retain copy在函数中对内存的影响,以及引用计数器的对内存控制管理机理,接下来专门章节会进行详细描述。