Objective-C—— @Property详解

实例变量:
属性其实说直白点就是 ivar + setter + getter(实例变量+存取方法),不过在OC中属性多了字面量这一系列特殊关键字使得OC属性有些不一样。数据库

成员属性咱们应该都使用过,好比如今定义一个Car类有name和speed成员变量:atom

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    @public
    NSString *name;
    NSInteger speed;
}
@end

在OC类的内部有一个偏移量,专门标记成员变量在内存中的所在位置。若是如今在添加一个新的成员变量在name的前面,那么就会出现偏移量总体便宜的问题,如今添加一个price实例:spa

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    @public
    NSInteger price;
    NSString *name;
    NSInteger speed;
}
@end

此时偏移量在内存中显示以下:代理

Car Car
name price
speed name
  speed

 

 

 

 

能够看到实例偏移量发生了改变,可是OC将实例变量做为一种存储偏移量所用的“特殊变量”,交个类对象(class object)保管,偏移量会在运行时查找,因此总能正确的找到偏移量。调试

 

@Propertycode

使用属性相比成员变量更加抽象,可以使用setter和getter对变量作更多的处理。对象

说一下属性的特性blog

 

@synthesize关键字内存

该关键字指定了属性的实例变量名称,而且根据存储语义(readwrite、readonly)系统自动合成setter和getter方法,固然也能够手写来覆盖系统提供的。get

@dynamic

该关键字告诉编译器不要为我合成setter和getter方法,这些方法将由我本身实现。固然咱们能够不实现这在编译阶段不会出现问题,直到运行时才会检查是否实现了setter和getter,若是没有实现就会抛出异常。

例如在CoreData中NSManagedObject子类的全部属性所有都是dynamic标记的,这是由于子类的某些属性不是真正的实例变量,而是对应背后的数据库,对NSManagedObject对象经过是属性访问时会自动使用KVC。

 

属性特性(语义)

属性的特质分为四类:

1.原子性:

  原子性就是指该属性是否为同步的,OC中大部分属性都是nonatomic(非原子性)的,若是不写nonatomic那么就会是原子性的。理论上来讲原子性属性的读写都将会是同步的,可是OC中atomic并不能必定肯定属性为同步的,若是真要进行同步操做,还要用更加深层次的同步锁API。并且atomic会很影响效率,因此通常都会写nonatomic。

2.读/写权限:

  读写为readonly和readwrite两种,前一种在系统只会合成getter方法,然后一种则会同时生成setter和getter。若是属性设置为了readonly属性,那么该属性是不能够修改的。

3.内存管理语义:

  assign:该方法只会针对“纯量类型”(CGFloat或NSInteger等)的简单赋值操做,id类型也要用assign,因此通常iOS中的代理delegate属性都会用assign来标示,如:

@property (nonatomic, assign)   id <UITableViewDataSource> dataSource;
@property (nonatomic, assign)   id <UITableViewDelegate>   delegate;

  strong: 使用该特性实例变量在赋值时,会释放旧值同时设置新值,对对象产生一个强引用,用MRC来讲就是引用计数+1。

  weak: 属性代表了一种”非拥有关系“,既不释放旧值,也不保留新值。用MRC就是引用计数不变,当指向的对象被释放时,该属性自动被设置为nil。这里多说一点,weak的runtime实现是经过hash表完成的,用变量名作键,一旦发现属性所指的对象被释放了,马上设置为nil。

  unsafe_unretained:和weak同样,惟一的区别就是当对象被释放后,该属性不会被设置为nil。因此是unsafe的。

  copy:和strong相似,不过该属性会被复制一个新的副本。不少时使用copy是为了方式Mutable(可变类型)在咱们不知道的状况下修改了属性值,而用copy能够生成一个不可变的副本防止被修改。若是咱们本身实现setter方法的话,须要手动copy。

4.方法名:

  getter = <name>

  setter = <name>

  方法名能够修改成咱们合成的方法名,可使存取方法语义更加符合应用场景。

  若是要在其它属性里面设置属性的话,仍是要符合属性特性,好比copy的话咱们仍是要手动copy一下属性。这里说一下构造方法里须要直接操做实例变量,而不该该调用setter和getter。

 

对象内部尽可能直接访问实例变量

首先说一下构造方法和析构方法中为何不能使用setter和getter,由于setter和getter是通过咱们包装过的方法,有可能增长一些判断,而若是子类调用父类的构造方法同时实现了本身的setter和getter,那么极可能就会出现问题。

经过属性访问实例变量会使用属性的字面语义,会使用KVO因此在执行效率上确定比直接调用实例变量慢,可是经过属性访问能够截获属性的获取和设置更加方便调试和控制。

通常在类内部推荐设置用setter 获取直接用实例变量。

这里再说一下惰性加载,所谓惰性加载就是指,属性会在第一次调用getter的时候初始化,以下:

-(NSString *)name
{
    if (!_name){
        _name = [[NSString alloc] init];
    }
    return _name;
}

那么此时就只可以经过getter来调用实例变量了。

相关文章
相关标签/搜索