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

Objective-C语法学习 第三天

2015-06-26 14:12 459 查看
关于属性

1.属性指的是一个对象的属性和特性(使用实例变量和访问方法构成实现属性的概念)。

使用属性编程可以:自动生成访问方法。

自动生成实例变量。

更简单地调用访问方法。通过.点操作符来调用访问方法,这个点是调用的对象setter和getter方法。

属性生命可以让编译器自动生成与数据成员同名的方法。

苹果的封装原则,如果要从类的外部访问多个实例变量的话,对每个实例变量都定义访问方法就可能很玛法吗。OC 2.0 增加了属性生命功能,这个功能是让编译器自动生成与数据成员同名的方法。使用一个@property就相当于在@interface接口文件中实现了实例变量对应的setter和getter方法。

@synthesize 实例变量(属性) 可以为这个实例变量(属性)实现在实现文件@implementation相应的setter和getter方法。其他方法可以直接在实现文件中实现,而不用在接口文件中生命。但是属性声明的情况下则不允许这种做法,接口部分中如果不使用@property进行定义,就无法在实现文件中使用@synthesize。

@property生命的属性名称和实例变量的名称是相同的,但有时候你也可能需要属性的名称和实例变量的名称不同,这时就需要为实例变量定义其他名称的属性。例如,我们可以通过下面的语句生成名为value的访问方法,并将其绑定到实例变量runningAverage    如下:

@synthesize  value = runningAverage;

(在子类中访问实例变量时,可以直接拿到访问实例变量,也可以通过self.通过访问方法来访问,但是如果父类的仅仅是在接口文件中只有实例变量而没有@property

则不可以通过self.来访问)上面括号中的完全是错的,刚才关系没有理清楚,重新写了个demo发现,在子类中访问父类的实例变量时只能通过访问方法来访问,不能直接访问父类的实例变量。图示如下:

这是demo总体关系,viewController是父类,testViewController是子类



下面这张图是viewController.m的赋值操作,看黄色警告就可以知道,虽然编译器通过了wo = 5;但是这个wo不是.h中的实例变量wo,下面的_wo才是.h中的实例变量wo,因为默认@synthesize生成的实现文件中的实例变量是在原来.h中实例变量前面加上了下划线。在这里也说一下@synthesize对实例变量的作用,@synthesize wo = wowowo,这样在.m中拿到self.wo和wowowo都是一个值,两者是相等的。


、、

下图是testViewController.m中,红色警告可以很清楚的支持了再子类中不能直接访问实例变量这个说法,只能通过self.访问方法的方式访问实例变量,而第22行打印的wo并不是父类中的实例变量,而是父类中那个被编译漏洞后的wo。



 

关于实例变量和属性的发展可以总结为三个阶段:

第一阶段就是在接口文件中@interface{}中写上实例变量,并且在{}下方写上这个实例变量岁对应的setter和getter方法,最后还需要在实现文件@implementation写上对应的实现方法setter和getter,这也是最为原始和繁琐的写法。

第二阶段就是在接口文件中@interface中只需要一行@property这个实例变量对应的属性,自动生成@interface文件所需要的setter和getter方法和对应在{}中的实例变量,最后在实现文件@implementation中写上一句@synthesize,自动生成实现方法setter和getter方法。这是第二个发展后的方法,只需要两行。

第三个阶段是只需要在@interface中写上一行@property,就可以自动生成对应的实例变量,以及@interface的setter和gettter还有@implementation中的setter和getter方法。这也是目前最简洁普遍的做法。

2.给属性指定选项

@property可用的选项  读写属性            readonly 只读

         
readwrite 读写

    赋值时的选项      assign 单纯赋值

retain  进行保持操作

    unsafe_unretained  同assign一样(用于ARC)

strong 同retain一样 (用于ARC)

weak 弱引用 (用于ARC)

copy 复制对象

   原子性操作           nonatomic  非原子性操作,非线程安全

3.赋值时的选项   

可以为可读写的@property设置选项,一共可设置6种 assign,retain,unsafe_unretained,strong,weak,copy.

(1)当@property的属性不是对象类型时只可以单纯的赋值  assign即可 通过使用@synthesize,会生成下面代码块A和B

(2)当@property的属性是对象类型,并且手动管理内存(现在一般遇不到这种情况)不指定选项的话,便于会有警告。三种 retain ,assign,copy

(3)当@property的属性是对象类型,且使用ARC管理内存

不指定选项会有警告提示。

指定了assign或者unsafe_unretained选项的情况下,只进行单纯的赋值,不进行保持操作。生命属性对应的实例变量时需要加上__unsafe_unretained修饰符。因为没有被保持,所以实例变量指向的内容可能会被释放掉而变成野指针,使用时候小心。

指定了strong或者retain选项的情况下,赋值操作后还会对传入的变量进行保持操作,这同下面代码块C的setter方法一样。实例变量在声明时候需要不加任何修饰符或者加上_strong 修饰符

指定了weak选项情况下,会生成相当于弱引用赋值的代码。实例变量在声明时候需要加上__ waek 修饰符

指定了copy情况下,回生成copy方法建立传入值的一份副本,并用这份副本给实例变量进行赋值。相当于下图代码块d。不使用输入的对象对属性进行赋值,而是生成对象的一个副本,使用这个副本对属性赋值。这种赋值方式只适用于对象类型,并且要求改对象遵循NSCopying协议,且能够使用copy方法。

(4)当@property是对象类型,且使用垃圾回收管理内存(用不到iOS开发 姑且不做描述)

代码块A
单纯的getter的定义

-(type)name{

return name;

}

代码块B  单纯进行赋值操作时的setter方法

-(void)setName:(type)obj{

name = obj;

}

代码块C  带有保持操作时的setter方法

-(void)setName:(type)obj{

if(name != obj){

【name release】;

name = 【obj retain】;

}

}

代码块D  带有copy操作时的setter方法

-(void)setName:(type)obj{

if(name != obj){

【name release】;

name = 【obj copy】;

}

}

4.原子性

nonatomic选项是在多线程环境下使用的。nonatomic表示访问方法是非原子的,原子性是多线程中的一个概念,如果说访问方法是原子的,那就意味着多线程环境下访问属性是安全的,在执行的过程中不可被打断,而nonatomic则正好相反,访问方法被nonatomic修饰的情况下,就意味着访问方法在执行的时候可被打断。缺省情况下访问方法是原子的。

当没指定nonatomic的时候,访问方法中需要使用lock和unlock来保证方法的原子性(_ex是系统提供的锁函数),通过使用lock和unlock能够保证每次最多有一个线程执行lock和unlock之间的代码,从而保证了原子性。

使用了retain而没有执行nonatomic选项时的情况

getter方法的定义

-(type)name{

【_ex lock】;//局部锁

type rtn = 【name retain】autorelease】;

【_ex unlock】;

return rtn;

}

setter方法的定义

-(void)setName:(type)obj{

[_ex lock];//局部锁

if(name != obj){

[name release];

name = [obj retain];

}

[_ex unlock];

}

5.通过点操作符访问属性

OC 2.0会在编译时把使用点操作符访问属性的过程理解为访问方法的调用。

点操作符只能用于类类型的实例变量,不能对id类型的变量应用点操作符。因为没有指定类型的情况下,编译器无法判断是否存在属性对应的访问方法。

点操作符可用于可读写的属性或只读的属性,不能用于只写的属性,这是因为属性声明中只能生命可读写的属性或只读的属性,不能声明只写的属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: