Objective-c 学习(2)

来源:互联网 发布:程序员的昵称 编辑:程序博客网 时间:2024/05/17 02:01

Objective-c学习(2

property属性

 

18Property属性

可让编译好器生成无泄漏和线程安全的访问实例变量的方法.

声明一个与数据成员同名的属性来省去读写函数的声明

@property (参数1,参数2)类型名字;

 

这里的参数主要分为三类:

读写属性(readwrite/readonly

setter语意(assign/retain/copy)决定了以何种方式对数据成员赋予新值

原子性atomicitynonatomic

 

 

先介绍一下默认的情况:

 

1assign:这个属性一般用来处理基础类型,比如intfloat等等,如果你声明的属性是基础类型的话,assign是默认的,你可以不加这个属性

assign 默认类型, setter方法直接赋值,而不进行retain操作

 

此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是可拷贝的。

 

对于assign来说,他的存取器代码是这样的:

@property (nonatomic, assign) NSString* myField

-(NSString*) myField

       return myField;

}

 

-(void) setMyField: (NSString*) newValue

{

       myField = newValue;

}

 

(2)  retain:首先要判断一下当前myField是否就是新赋值来的对象,如果不是要将自己release掉,之后才会进行赋值及retain,具体实现如下:

 

指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)

 

@property (nonatomic, retain) NSString* myField

-(NSString*) myField

    return myField;

}

-(void) setMyField: (NSString*) newValue

       if  (newValue != myField)

       {

        [myField release];

        myField = [newValue retain];

    }

}

 

 

3copy:这个会自动生成你赋值对象的克隆,相当于在内存中新生成了该对象的副本,这样一来,改变赋值对象就不会改变你声明的这个成员变量了

 

它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。

 

-(void) setMyField: (NSString*) newValue

       if  (newValue != myField)

       {

        [myField release];

        myField = [newValue copy];

    }

}

 

 

 

4readonly:只生成getter不会有setter方法, readonly关键字代表setter不会被生成,所以它不可以和 copy/retain/assign组合使用。

 

此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。

 

5readwrite:这个属性是默认的情况,会自动为你生成存取器

 

此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。

 

 

6natomic:默认是有该属性的,这个属性是为了保证程序在多线程情况,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题

 

7nonatomic:如果该对象无需考虑多线程的情况,请加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率

 

指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了nonatomic,那么访问器只是简单地返回这个值

 

 

8dynamic关键字是告诉编译器由我们自己来实现访问方法。

       如果使用的是@synthesize,那么这个工作编译器就会帮你实现了。

 

 

基本使用规则如下:

使用assign:对基础数据类型(NSIntegerCGFloat)和C数据类型(int, float, double, char,等等)

使用copy:对NSString

使用retain:对其他NSObject和其子类

 

 

19@synthesize

       @systhesize xxx:为这个心属性自动生成读写函数

 

 

 

 

20,浅复制

如果是copy的是一个NSArray?比如,

NSArray *array = [NSArrayarrayWithObjects:@"hello",@"world",@"baby"];

NSArray *array2 = [array copy];

 

这个时候,,系统的确是为array2开辟了一块内存空间,但是我们要认识到的是,array2中的每个元素,只是copy了指向array中相对应元素的指针。这便是所谓的"浅复制"

了解到这一点非常重要....

 

浅复制和深复制是对于包含对象成员的对象而言的。

浅复制:只复制对象本身,对象的成员只复制指针

深复制:在浅复制的基础上,同时复制对象的成员

 

例子

@interface A : NSObject {

}

 

@property (nonatomic, retain) NSString * member;

- (A *) shadowCopy;

- (A *) deepCopy;

 

@end

 

@implementation A

@synthesize member;

- (void) dealloc {

    [self.member release];

    [super dealloc];

}

 

- (A *) shadowCopy {

    A * ret = [A alloc];

    ret.member = self.member;

    return [ret autorelease];

}

 

- (A *) deepCopy {

    A * ret = [A alloc];

    ret.member = [NSString stringWithString:self.member]; // 这就是本质区别

    return [ret autorelease];

}