博客> @property详解
@property详解
2017-12-11 19:18 评论:0 阅读:695 tianya2416
属性 property

1.简介

Objective-C语⾔言关键词,与@synthesize配对使⽤用。 xcode4.5以及以后的 版本,@synthesize可以省略。提供成员变量的访问⽅方法的声明、控制成员 变量的访问权限、控制多线程时成员变量的访问环境 。

2.格式

声明property的语法为:
@property (参数1,参数2,...) 类型 名字; 如:
@property(nonatomic,retain) UIWindow *window;
其中参数主要分为三类:
• 读写属性: (readwrite/readonly/setter = /getter = )
• setter语意:(assign/retain/copy)
• 原⼦子性: (atomicity/nonatomic)
• nullability annotations: (nonnull/nullable) [ Enter your link description here: ]((http://

www.cocoachina.com/ios/20150601/11989.htm)

各参数意义如下:

- readwrite 产⽣生setter\getter⽅方法
- readonly 只产⽣生简单的getter,没有setter, 默认的读写属性  
- setter = 指定⽣生成setter⽅方法的名字
- getter = 指定⽣生成getter⽅方法的名字
- assign   默认类型,setter⽅方法直接赋值,⽽而不进⾏行retain操作,适⽤用于基 本数据类型, 对对象类型, 不会发⽣生引⽤用计数变化
- retain  setter⽅方法对参数进⾏行release旧值,再retain新值
- copy  setter⽅方法进⾏行Copy操作,与retain⼀一样
- atomic 保证多线程访问下的安全,但浪费系统资源,原⼦子性控制的默
认设置
- nonatomic 禁⽌止多线程,变量保护,提⾼高性能
- nonnull 表⽰示对象可以是NULL或nil
- nullable 表⽰示对象不应该为空

3.参数对⽐比

3.1 atomic 和 nonatomic

atomic 是默认的属性,表⽰示对对象的操作属于原⼦子操作,主要是在多线程
的环境下,提供多线程访问的安全。我们知道在多线程的下对对象的访问都 需要先上锁访问后再解锁,保证不会同时有⼏几个操作针对同⼀一个对象。如果 编程中不涉及到多线程,不建议使⽤用,因为使⽤用atomic⽐比nonatomic更耗费系 统资源。

nonatomic 表⽰示访问器的访问不是原⼦子操作,不⽀支持多线程访问安全,但 是访问性能⾼高。

 屏幕快照 2016-04-08 18.46.09.png

atomic是默认⾏行为,所以这两⾏行代码是等价的。

3.2 readwrite 和readonly

readwrite 是默认的属性,表⽰示可以对对象进⾏行读和写,会⽣生成对象相应的 setter和getter⽅方法。
readonly 表⽰示只允许读取对象的值,只会⽣生成对象的getter⽅方法。

 屏幕快照 2016-04-08 18.47.20.png

readwrite是默认⾏行为,所以这两⾏行代码等价

3.3 retain,assign和copy

retain 表⽰示对NSObject和及其⼦子类对象release旧值,再retain新值,使对 象的应⽤用计数增加⼀一。
此属性只能使⽤用于obejective-c类型对象,⽽而不能⽤用于Core Foundation对 象。(retain会增加对象的引⽤用计数,⽽而基本数据类型或者Core Foundation对 象都没有引⽤用计数,把对象添加到数组中时,引⽤用计数将增加1)。

- (void) setOldValue: (NSString*) newValue {
     if (newValue !=oldValue) {
    [oldValue release];
    oldValue = [newValue retain]; }
}

@property (retain) NSObject *obj; 
@property (atomic,retain) NSObject *obj;
@property (nonatomic,retain)NSObject *obj;
@property (nonatomic,retain,readwrite) NSObject *obj;

assign 是默认属性,只可以对基本数据类型(如CGFloat, NSInteger,Bool,int,代理对象)等使⽤用。该⽅方式会对对象直接赋值⽽而不会进⾏行 retain操作。

copy 表⽰示重新建⽴立⼀一个新的计数为1的对象,然后释放掉旧的值。 都知道retain是对指针的拷⻉贝,copy是对内容的拷⻉贝。⽐比如:NSString 对象 的地址为0x100,其内容为“string”,如果使⽤用copy到另外⼀一个NSString对 象,则会⽣生成另外⼀一个地址为0x110的对象,只不过内容仍然是’string“。如果 使⽤用retain到另外⼀一个NSString对象,则该对象的地址仍然为0x100,只不过 该对象的计数变为2.

 屏幕快照 2016-04-08 18.49.54.png

对int 来说,atomic assign都是默认⾏行为,所以这三⾏行是等价的。

3.4 strong 和 weak

在ARC的模式下,对象声明时需要加⼊入strong和weak,⽅方便内存的⾃自动管 理。默认情况下是strong类型。 strong 强引⽤用,默认的属性,类似于retain,其实是⼀一个相对的概念,就是 ⼀一个引⽤用。如果有⼀一个强引⽤用持有该对象,则该对象就不能被释放。默认的 所有实例变量和局部变量都是strong指针。 weak 弱引⽤用,类似于assign,弱引⽤用除了不决定对象的存亡外,其他与强 引⽤用相同。即使⼀一个对象被持有⽆无数个若引⽤用,只要没有强引⽤用指向他,那 麽其还是会被清除,它不是对象的拥有者。其值会在对象被释放后⾃自动设置 为nil。 weak 指针主要⽤用于“⽗父-⼦子”关系,⽗父亲拥有⼀一个⼉儿⼦子的strong指针,因此⽗父 亲是⼉儿⼦子的所有者;但为了阻⽌止所有权循环,⼉儿⼦子需要使⽤用weak指针指向⽗父 亲。典型例⼦子是delegate模式,你的ViewController通过strong指针 (self.view)拥有⼀一个UITableView, UITableView的dataSource和delegate都 是weak指针,指向你的ViewController。

3.5 nonnull 和 nullable

我们都知道在swift中,可以使⽤用!和?来表⽰示⼀一个对象是optional的还是non- optional,如view?和view!。⽽而在Objective-C中则没有这⼀一区分,view即可表 ⽰示这个对象是optional,也可表⽰示是non-optioanl。这样就会造成⼀一个问题: 在Swift与Objective-C混编时,Swift编译器并不知道⼀一个Objective-C对象到 底是optional还是non-optional,因此这种情况下编译器会隐式地将Objective- C的对象当成是non-optional。  为了解决这个问题,苹果在Xcode 6.3引⼊入了⼀一个Objective-C的新特性: nullability annotations。这⼀一新特性的核⼼心是两个新的类型注释:nullable 和nonnull。从字⾯面上我们可以猜到,nullable表⽰示对象可以是NULL或 nil,⽽而nonnull表⽰示对象不应该为空。当我们不遵循这⼀一规则时,编译器 就会给出警告。 在任何可以使⽤用const关键字的地⽅方都可以使⽤用nullable和nonnull,不 过这两个关键字仅限于使⽤用在指针类型上。⽽而在⽅方法的声明中,我们还可以 使⽤用不带下划线的nullable和nonnull

@property (nonatomic, copy, nonnull) NSArray * items;
 @property (nonatomic, copy) NSArray * __nonnull items;

推荐使⽤用nonnull这种⽅方式,这样可以让属性声明看起来更清晰。

4.事例说明

@prperty只不过是给编译器看的⼀一种指令,它可以编译之后为你⽣生成相应 的getter和setter⽅方法。

4.1 getter分析

@property(nonatomic,retain)test* thetest; 
@property(nonatomic ,copy)test* thetest;

等效代码:

-(test*)thetest
 {
    return thetest;
 }

@property(retain)test* thetest; 
@property(copy)test* thetest;

等效代码:

-(test*)thetest {

    [thetest retain];
    return [thetest autorelease];
}

4.2 setter分析

   @property(nonatomic,retain)test* thetest; 
    @property(retain)test* thete    

等效于:

-(void)setThetest:(test *)newThetest { if (thetest!= newThetest) { [thetest release]; thetest= [newThetest retain]; } }

    @property(nonatomic,copy)test* thetest; 
    @property(copy)test* thetest;

    等效于:
    -(void)setThetest:(test *)newThetest 
    {
        if (thetest != newThetest)
         { 
        [thetest release];
        thetest= [newThetest copy]; }
        }

4.3 assign分析

@property(nonatomic) NSString *name 如果你这样写,那将会有如下警告: 因为是⾮非gc的对象,所以默认的assign修饰符是不⾏行的,⽽而由于atomic, readwrite,assign是默认的,所以以下写法也是可以的:

 @property NSInteger maxConcurrentOperationCount;
    等效代码:
@property(atomic,assign,readwrite) NSInteger maxConcurrentOperationCount;

4.4 代码分析

//代码⼀:

    @interface BaseClass : NSObject
    { 
        @public NSString *_name; 
    }
    @property(nonatomic,copy,readonly) NSString *name; 
  //这⾥里使⽤用的是 readonly,所有会声明geter⽅方法
    -(void) setName:(NSString*)newName;

//代码⼆:

    @interface BaseClass : NSObject
    { 
    `@public NSString *_name;
     }
    @property(nonatomic,copy,readonly) NSString *name; readonly,
    但是不会⽣生成getter⽅方法,因为你下⾯面⾃自⼰己定义了getter⽅方法。
    -(NSString*) name; 
    //getter⽅方法是不是只能是name呢?不⼀一定,你打开 Foundation.framework,找到UIView.h,看看⾥里⾯面的property就明⽩白了) 
    -(void) setName:(NSString*)newName;

//代码三:

    @interface BaseClass : NSObject
    {
     @public NSString *_name; }
    @property(nonatomic,copy,readwrite) NSString *name; 
    //这⾥里编译器会我们 ⽣生成了getter和setter

//代码四:

    @interface BaseClass : NSObject
    {
     @public NSString *_name; 
    }
    @property(nonatomic,copy) NSString *name; 
    //因为readwrite是默认⾏行为, 所以同代码三

上⾯面四段代码是等价的,接下来,请看下⾯面四段代码:

//代码⼀一:

    @synthesize name = _name
     //这句话,编译器发现你没有定义任何getter 和setter,所以会同时会你⽣生成getter和setter

//代码⼆二:

    @synthesize name = _name;

     //因为你定义了name,也就是getter⽅方法,所 以编译器只会为⽣生成setter⽅方法,也就是setName⽅方法。
    -(NSString*) name
    {
    NSLog(@"name");
    return _name; 
    }

//代码三:

    @synthesize name = _name;
    只会为你⽣生成getter⽅方法
    //这⾥里因为你定义了setter⽅方法,所以编译器
    -(void) setName:(NSString *)name{ NSLog(@"setName");
    if (_name != name)
     { 
    [_name release];
    _name = [name copy];
     }
    } 

//代码四:

@synthesize name = _name; 
//这⾥里你⾃自⼰己定义了getter和setter,这句话没 ⽤用了,你可以注释掉。
    -(NSString*) name
{ 
    NSLog(@"name");
    return _name; 
    }

    -(void) setName:(NSString *)name
{
    if (_name != name)
    {
        [_name release];
        _name = [name copy];
    }
}

总结⼀一下,如果你⾃自⼰己实现了getter和setter的话,atomic/nonatomic/retain/ assign/copy这些只是给编译的建议,编译会⾸首先会到你的代码⾥里⾯面去找,如 果你定义了相应的getter和setter的话,那么好,⽤用你的。如果没有,编译器 就会根据atomic/nonatomic/retain/assign/copy这其中你指定的某⼏几个规则去 ⽣生成相应的getter和setter。

5.总结

a) 什么时候⽤用assign、什么时候⽤用retain和copy呢?

推荐做法是NSString⽤用copy,delegate⽤用assign,⾮非objc数据类型,⽐比如int, float等基本数据类型⽤用assign(默认就是assign),⽽而其它objc类型,⽐比如 NSArray,NSDate⽤用retain。

b)该⽤用atomic还是⽤用nonatomic?

atomic,如其名,它会保证每次getter和setter的操作都会正确的执⾏行完毕, ⽽而不⽤用担⼼心其它线程在你get的时候set,可以说保证了某种程度上的线程安 全。但是,仅仅靠atomic来保证线程安全是很天真的。要写出线程安全的代 码,还需要有同步和互斥机制。 ⽽而nonatomic就没有类似的“线程安全”(我这⾥里加引号是指某种程度的线程 安全)保证了。因此,很明显,nonatomic⽐比atomic速度要快。这也是为什 么,我们基本上所有⽤用property的地⽅方,都⽤用的是nonatomic了。

c)选择readonly还是readwrite? 选择哪个不⽤用我说了吧

d) 是否设置nonnull 或者 nullable 如果⼯工程项⺫⽬目是swift和objective-c混合编译,那就需要给编译器指明类型

收藏
0
sina weixin mail 回到顶部