------------早期GCC版本------------
--@property A作用就是让编译器在h文件声明A 的setter/getter方法;
--@synthesize A作用就是让编译器在m文件生成A 的setter/getter方法;(如果自己实现了setter/getter方法,则以自己实现为准)
--要求必须要成员变量A 对应属性;或者将名称不一样成员变量_A对应属性A,即@synthesize A = _A;
--另外,属性的retain、assign、copy等修饰词就是在setter方法里retain/release等额外操作;
------------现在LLVM版本------------
--@property A作用强大了,除了原有作用;同时还Default synthesis of @property instance variables and accessor methods;具体:
1..如果发现m中没有@synthesize,则"Autosynthesized A= _A"(补上synthesize和匹配的_A);有@synthesize,不做处理;
2.根据m中@synthesize中匹配的实例变量查看有没有,若没有创建之。(@synthesize A匹配的实例变量为A;@synthesize A = _A 匹配的实例变量为_A)
--上叙俩规则根据例子总结,未找到相关文档说明:
--例子1;只有@property A ;那么m中 _A 能用,A 不能用;
--例子2;有@property A + 成员变量A; 那么 _A 能用,A能用;
--例子2: 有@property A + @synthesize A;那么 _A 不能,A 能用;
--例子3;有@property A + @synthesize A + 成员变量_A;那么 _A 能用,A 都能用;
--例子4;有@property A + @synthesize A=_A + 成员变量_A; 那么 _A 能用,A 不能用;
--一个经典例子,类中有属性@property(nonatomic,strong)IBOutlet UIButton *aButton; 和成员变量IBOutlet UIButton *_aButton; 没有@synthesize;他俩分别关联button1,和button2,运行程序,不管是self.aButton 还是_aButton都是指向button1;说明@property在编译的时候起作用,将_aButton 和属性aButton关联为一个。如果属性和成员变量是一样的,则一个关联button1,另一个也关联了。
------------类别中的属性property ------------
--类与类别中添加的属性要区分开来,因为类别中只能添加方法,不能添加实例变量。经常会在ios的代码中看到在类别中添加属性,这种情况下,是不会自动生成实例变量的。例:UINavigationController.h中会对UIViewController类进行扩展
[objc] view plaincopy
@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,retain) UINavigationItem *navigationItem;
@property(nonatomic) BOOL hidesBottomBarWhenPushed;
@property(nonatomic,readonly,retain) UINavigationController *navigationController;
@end
这里添加的属性,不会自动生成实例变量,这里添加的属性其实是添加的getter与setter方法。
注意一点,匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)
============修饰词============
主要分为三类:
1.原子性(Atomicity)包含:nonatomic;
2.读写属性(Writability)包含:readwrite / readonly;
3.setter语义(Setter Semantics)包含:assign / retain / copy;
------原子性:
nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问。默认值是atomic,为原子操作。(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)
------读写属性:
readwrite / readonly:决定是否生成set访问器,readwrite是默认属性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用。
注意:readwrite/readonly配合使用:属性在外部是只读,自己使用时读写-->re-declare the property in a class extension
[objc] view plaincopy
@property(nonatomic,readonly)NSString *myName; //在.h 中
self.myName = @"ss"; 不能用;而 _myName = @"ss" 能用 //在.m中
//re-declare the property in a class extension
@interface ViewController ()
@property(nonatomic,readwrite)NSString *myName;
@end
self.myName = @"ss"; 和 _myName = @"ss" 都能用
------setter语义:
这些属性用于指定set访问器的语义,也就是说,这些属性决定了以何种方式对数据成员赋予新值。
--assign:直接赋值,索引计数不改变,适用于简单数据类型,例如:NSIngeter、CGFloat、int、char等。
--retain:指针的拷贝,使用的是原来的内存空间。对象的索引计数加1。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。
--copy:对象的拷贝,新申请一块内存空间,并把原始内容复制到那片空间。新对象的索引计数为1。此属性只对那些实行了NSCopying协议的对象类型有效。
很多Objective-C中的object最好使用用retain,一些特别的object(例如:string)使用copy。
============自定义setter/getter方法============
[html] view plaincopy
// 1,当把语义特性声明为assign时,setter和getter时方法内部实现
- (void)setName:(NSString *)name{
_name = name;
}
- (NSString *)name{
return _name;
}
//2,当把语义特性声明为retain时,setter和getter方法内部实现
- (void)setName:(NSString *)name{
if (_name != name) {
[ _name release];
_name = [name retain];
}
}
- (NSString *)name{
return [[ _name retain] autorelease];
}
//3,当把语义特性声明为copy时,setter和getter方法内部实现
- (void)setName:(NSString *)name{
if (_name != name) {
[ _name release];
_name = [name copy];
}
}
- (NSString *)name{
return [[ _name retain] autorelease];
}
注意自定setter方法的书写,以前为了“安全”都在releae后面赋了一个nil的值。这样写是错误的,尤其对于retain的语音,因为有可能别的对象retain的它持有的对象,结果值被置为nil了。另不用担心初始的时候_name 就release了一次,因为类的成员中对象的初始值都是nil。
[html] view plaincopy
if (_name != name) {
[ _name release];
_name = nil;
_name = [name retain];
}
}