有时候在代码中遇到这样的Autosynthesized property 警告:
Autosynthesized property 'datasource' will use synthesized instance variable '_datasource', not existing instance variable 'datasource’.
警告的意思大概是在提醒开发者 ,在合成属性 datasource变量将会使用编译器自动生成的带下划线带_datasource 的实例变量,
而不存在datasource 这个实例变量。
出现这个警告的原因:
先说明一下成员变量和属性声明的原理:
在iOS5之前,苹果使用的是GCC编译器, 该编译器要求开发者在进行属性@property声明的同时还要进行 @synthesize 指令来告诉编译器为该变量生成setter/getter 方法,并且该编译器只支持非ARC 模式的内存管理,需要开发者在代码中手动添加retain
,release 来管理对象的内存
在iOS5之后,苹果把GCC 编译器换成了LLVM 编译器,该编译器在进行属性声明的时候会自动生成一个带下划线的实例变量,并且不再需要@synthesize 指令就可以自动生成setter/getter
方法来访问该属性变量,而且该属性变量 可以直接使用带下划线的实例变量进行访问,也可以用self的点语法进行间接的访问,
注意: 用带下划线的实例变量访问与用self的点语法进行间接的访问的区别:
(1) 带下划线的实例变量实际上 访问的是属性声明时在编译器进行编译自动生成的代下划线的那个实例变量的直接访问,而self的点语法实际上是间接调用属性生成的setter/getter 方法(oc 语法中的点语法的特性),是间接访问
(2) 带下划线的实例变量的访问不会使内存计数器加1,而self的点语法的访问会使其内存计数器加1;
(3) @property 的声明中,编译器自动生成的setter/getter 方法 是有优先级的,它首先查找当前的类中用户是否已定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。
也就是说你在使用self点语法 时是在调用方法,它会让内存计数器加1, 而 带下划线的实例变量并不会使内存计数器加1.
注意:
(1)如果在.h文件中这样声明一个变量:
@interface MyviewController :UIViewController
{ Nsstring *namestring;
}
但是如果在实现文件.m 文件中用self.namestring 访问时,编译器会报错,因为oc中的点语法是间接调用属性的getter/setter 方法,但是此处在.h文件中只是声明了一个成员变量,并没有生成getter/setter 方法 ,所以编译器会报错,此时应该使用self->namestring 进行访问。总结一句:getter/setter 方法 只是在进行属性声明的时候自动生成的,iOS5之后也不需要再通过@synthesize
指令来生成getter/setter 方法,并且iOS5之后增加了支持ARC模式的内存管理,通过在声明属性时添加strong /weak 修饰词进行标记来管理内存。
(2)使用@property定义变量ivar有三种情况
1)没有合成@synthesized ,则系统会通过Autosynthesized自动合成一个_ivar
2)如果使用@synthesized ivar;则声称的变量为ivar,此时_ivar 是不存在的
3)如果使用@synthesized ivar = _ivar;则声明的变量为_ivar。
出现该警告的原因是:由于我在.h文件中用属性@property 声明了一个变量,又在.m文件中的{}中声明了同名的成员变量,在编译器进行编译的时候,先编译.h文件,会自动生成了一个带下划线的实例变量,当编译.m 文件时检索到该成员变量 ,此时编译器就会提示一个警告,说明合成属性将会使用_datasource 变量, 但并不存在.m文件中声明的该datasource 变量。
解决方法: 由于这个变量是只有该类进行访问的,所以我将.h文件声明的属性语句注释掉, 在实现文件中就直接对该成员变量进行访问就可以了