iOS RunTime 学习记录3_属性、实例变量、修饰符

前言:我是参考 南峰子 的博客加上自己理解写的,原著专辑大家自己可看:http://southpeak.github.io/categories/objectivec/

一、 先说说属性(property)和成员变量 (instance var(Ivar))的区别

其实主观上,自己认为:属性就是我们平时在.h中用@property关键字声明的东西,而实例变量是我们在.h.m中用{}声明的东西。

@interface ViewController : UIViewController{
    
    NSInteger integer1;         //实例变量
}

@property (assign,nonatomic) NSInteger integer2;    //实例属性
  1. 一般我们在使用@property声明的属性,如果没在.m文件中使用@synthesize同步的话,系统会默认生成一个与属性对应的实例变量。如上面的代码,我们在.m中可以直接通过访问_integer2。如果使用在.m文件中使用@synthesize同步的话,如:@synthesize integer2,那么属性对应的成员变量就不是_integer2,而是integer2,就得到一个和属性名称一样的实例变量。当然@synthesize语句也可以用户指定当前属性和那个成员变量绑定,如@synthesize integer2 = integer1,这样写就制定了属性integer2和实例变量integer1绑定了。
  2. 在我们使用self.integer2,因为integer2是通过使用@property来声明的属性,我们使用的时候一般是通过self.来使用,其实是系统分装的setter 和 getter方法,我们看是通过一个小点.访问属性,其实执行是方法(据说这是当时OC设计者估计和Java学的),通过方法去给对应的实例变量(_integer2)读取赋值的。为什么这样做了,其实是我们读取写入的时候会更具我们跟在@property后面括号(assign,nonatomic)声明的关键字去管理实例变量的内存,如retain,copy等。
  3. 如果我们直接访问实例变量可以通过直接调用实例变量的名字或通过self->实例变量名字访问,这时候的内存管理方式我们没有指定,其实就是直接赋值(assign),而属性可以通过修饰词加上getter和setter方法实现丰富的内存管理方式。

PS:以前碰到一个小问题http://www.jianshu.com/p/ded24cade177可以直观的解释

二、修饰符

逃也逃不掉,该弄懂的还是要弄的

1.原子性(Atomicity)包含:nonatomic;
2.读写属性(Writability)包含:readwrite / readonly;
3.setter语义(Setter Semantics)包含:assign / retain / copy;

1. 原子性
nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问。默认值是atomic,为原子操作。(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)

2. 读写属性
readwrite / readonly:决定是否生成set访问器,readwrite是默认属性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用
注意:readwrite/readonly配合使用:属性在外部是只读,自己使用时读写使用self->实例变量直接读或写

3. setter语义
这些属性用于指定set访问器的语义,也就是说,这些属性决定了以何种方式对数据成员赋予新值。
--assign:直接赋值,索引计数不改变,适用于简单数据类型,例如:NSIngeter、CGFloat、int、char等。
--retain(strong):指针的拷贝,使用的是原来的内存空间。对象的索引计数加1。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。
--copy:对象的拷贝,新申请一块内存空间,并把原始内容复制到那片空间。新对象的索引计数为1。此属性只对那些实行了NSCopying协议的对象类型有效。

  • 很多Objective-C中的object最好使用用retain(strong),一些特别的object(例如:string)使用copy

三、实例变量 和 属性在RunTime中关联的方法

实例变量: 英文Instance var 简写:Ivar,在OC中也是使用结构体objc_ivar定义一个Ivar,其结构体定义如下:

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}                                                            OBJC2_UNAVAILABLE;

关于成员变量的一些方法:

/** 获取成员变量名 */
OBJC_EXPORT const char *ivar_getName(Ivar v) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

/**获取成员变量类型编码 */
OBJC_EXPORT const char *ivar_getTypeEncoding(Ivar v) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

/** 获取成员变量的偏移量 */
OBJC_EXPORT ptrdiff_t ivar_getOffset(Ivar v) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

对于类型id或其它对象类型的实例变量,可以调用object_getIvar
和object_setIvar来直接访问成员变量,而不使用偏移量

属性: property ,在OC中使用结构体objc_property定义objc_property_t表示属性(我没有找到objc_property结构体的具体声明)。另外,OC中使用结构体objc_property_attribute_t定义一个属性的描述信息,它的定义如下:

/// Defines a property attribute
typedef struct {
    const char *name;           /**< The name of the attribute */
    const char *value;          /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;

属性常用的方法:

// 获取属性名
const char * property_getName ( objc_property_t property );

// 获取属性特性描述字符串
const char * property_getAttributes ( objc_property_t property );

// 获取属性中指定的特性
char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );

// 获取属性的特性列表
objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount )1

你可能感兴趣的:(iOS RunTime 学习记录3_属性、实例变量、修饰符)