Effective Objc : Object-C 中 @property 详解

在一个类中,为了类的工作运转,拥有了多个成员变量,我们能够像Java或者C一样的声明他们:

@interface WGCell : UITableViewCell
{
    NSString *_cellName;
}
@end
在这种声明方法下,之前的编译器会将多个成员变量线性地排列在内存空间中,因此,如果添加或删除了某个变量声明,整个项目需要进行重编译才能保证项目的兼容性。Objc 对此的解决方案是,让类对象的成员变量储存了自己在内存中的offset,在运行时中,若发现类成员变量声明发生了改变,所有成员变量储存的offset也会相应地更新,编译器就能顺利访问到该成员变量。运用这种传说中的nonfragile ABI技术,我们可以在运行时添加成员变量到一个类中,这为我们的 扩展协议技术 与 成员声明隐藏 创造了条件。

---------------背景与主题分割线---------------------------


@property 由来与使用


Objc中,我们偏向于使用成员变量访问方法去访问成员变量,而不是直接访问成员变量,方法的命名遵守着严格的命名规范,因此,我们可以定义一种自动生成访问方法的语法,这就是@property 语法的由来。上述的声明语句,我们可以修改为        

@interface WGCell : UITableViewCell
@property NSString *cellName;
@end

若在类的定义中使用了@property 语法,就等同于为成员变量生成了相应的getter与setter方法,这种技术叫做 autosynthesis(= = 真心不知道怎么翻译) 

@interface WGCell : UITableViewCell
- (NSString*)cellName;
- (void)setCellName;

@end
这些方法,也能够通过我们熟悉的点语法来进行调用

cell.cellName = @"呵呵";
同时,当使用了@property语法时,编译器会自动地为这些访问方法添加相应的成员变量,在上面的例子中,编译器会自动为这个类生成一个相应的成员变量 _cellName(XCode4.5后),当然,为了满足强迫控们的需求,我们可以在类的实现中制定生成的变量名

@implementation WGShoppingFeedsCell
@synthesize cellName = myCellName;
@end

当然,还是建议使用系统默认生成的变量名,这样能够统一整个项目的代码风格,增强代码可读性~ 而如果反感系统自动生成方法和变量,我们也能和系统说,不用了,省省吧

@implementation WGShoppingFeedsCell
@dynamic cellName;
@end

这样子系统会忽略访问方法和变量还没生成这个事实,照常编译,并相信你会把访问方法和变量实现,并对一切对cellName的访问不提出任何警告。


@property属性详解


而另一方面,通过对于property的属性的数值,我们能控制生成的访问方法的类型,如

@property(nonatomic,readwrite,copy) NSString *cellName;

四种类型的属性会被应用:

Atomicity属性

atomic 即是原子性,通过加入线程锁来保证生成的访问器方法是线程安全的,每个@property 都是默认为atomic属性的,但我们能看到现在几乎所有的@property都会加上nonatomic 属性,即取消线程安全保护,因为atomic属性会造成性能问题,在ios开发中不适用,而使用了nonatomic后,若需要的话,我们应该自己保证访问器的线程安全。

Read/Write属性:

readwrite: 会生成getter与setter方法

readonly:只生成getter方法,可以用于一个只读的公共成员变量,也能在扩展协议中将其指定为readwrite

内存管理类属性:

assign:访问器只是直接进行赋值操作,一般用于CGFloat,NSInteger

strong: 在ARC中运用,这个属性表明成员变量拥有指向的对象,如果调用了他的set方法,成员变量新指向的对象的引用计数加一,原来指向的对象的引用计数减一,然后成员变量就指向了新的对象

weak:在ARC中运用,与strong相反,这个属性表明成员变量不拥有指向的对象,它不对新指向的对象进行retain操作,也不对原先指向的对象进行release操作,与assign类似,不过当其指向的对象引用计数为0被销毁时,它会自动置为nil

unsafe_unretained: 这是ARC时代的assign,当对象销毁时,它不会变为nil的

copy: 当指向新对象时,他不会指向新对象的内存地址,进行retain与release操作,而是重新创建一份内存空间,将对象copy到新对象中,并将引用计数设为1,指向复制后的对象。这个属性多用于NSString*,为了防止赋值的对象为NSMutableString,导致对象在运行时可能的修改造成的问题

方法名属性:

getter=<name> 修改getter方法名

        setter = <name> 修改setter方法名

如:

@property(nonatomic,getter=isOn) BOOL on;


注意事项:


在类的实现中重载了@property对象的setter方法与类的初始化方法,若是直接对类成员变量进行赋值,需要根据成员变量的property属性的规则进行赋值,否则就容易出现bug,如

@property (copy) NSString *cellName;

-(id)initWithCellName:(NSString*)cellName;

其定义应该为
-(id)initWithCellName:(NSString*)cellName
{
    if(self = [super init])
    {
        _cellName = [cellName copy];
    }
}
为什么不能用以下代码解决呢
self.cellName = cellName;

若可能继承的子类的setter方法有额外的限制,比如除了 值为"wangif" 的NSString 之外,所有赋值都会抛出异常,那代码就会在这个init方法中出现错误了,因此,所有在init方法中对成员变量的赋值,都建议用直接赋值方法



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值