IOS 的属性剖析(点语法操作)
来源:互联网 发布:打碟软件 编辑:程序博客网 时间:2024/05/16 15:18
在C++中,没有属性的概念,只有setter,getter的方式来对类成员变量进行操作。
如:
class gloox
{
public:
gloox(){};
~gloox(){};
int getCount(){return m_count;};
void setCount(int acount){m_count = acount;};
private:
int m_count;
}
再来看Object-C中的设计。
.h文件
#import <Foundation/Foundation.h>@interface OCDeomer : NSObject{ NSInteger ct;}-(void)setCount:(NSInteger) tcount;-(NSInteger)count;@end
.m文件
@implementation OCDeomer-(void)setCount:(NSInteger) tcount{ ct = tcount;}
-(NSInteger)count{ return ct;}
@end
调用,点语法的方式:
- (IBAction)onremove:(id)sender { OCDeomer* dm = [[OCDeomer alloc]init]; //OC的调用方式
[dm setCount:20]; NSInteger tc = [dm count]; NSLog(@"tc = %i",tc); //点语法的访问方式
dm.count = 40;//默认调用setCount 即setter方法。 tc = dm.count;//默认调用getter方法。 NSLog(@"tcc = %i",tc); [dm release];}
上面是手动写的setter,getter方法
在OC中,@property 类型 方法名 在编译的时侯会自动的展开为setter getter 的方式。展开的规则:展开为setter时,默认为set+方法名(首字母大写),getter时,方法名跟属性名一样。如上面的例子:
@property NSInteger count;编译时展开为下面的setter 和getter方法。
-(void)setCount:(NSInteger) tcount;
-(NSInteger)count;
修改成如下形式,再进行测试,如果一样。
#import <Foundation/Foundation.h>@interface OCDeomer : NSObject{ NSInteger ct;}//-(void)setCount:(NSInteger) tcount;//-(NSInteger)count;@property NSInteger count;@end
光有属性还没完事,OC还为我们节省了不少setter 和getter的实现方式。如:
@synthesize count;
这句就相当于下面这两个方法的实现:
-(void)setCount:(NSInteger) tcount
{
}
-(NSInteger)count
{
}
了解这些特性之后,就可以进行组合使用,如
1、使用@property 和@synthesize
2、也或以使用@property 和setter,getter的实现。
3、或setter,getter的声明和@synthesize的组合
还有一点需要注意的是self.这个访问操作。
self.count 与[self count] 实际上是操作属性,对属性的操作最终都会转为setter,getter操作,与在类中调用类成员是有区别的。
因此在处理类成员变量时,当成员名字与属性名字相同的时候,就要相当注意self.与没有self.时的操作了。
下面举个例:
#import <Foundation/Foundation.h>@interface OCDeomer : NSObject{ UIImage *img;}@property (retain) UIImage *img;//注意这里属性名与类成员变量名相同,注意这里还使用了retain关键词-(void)test;//主要用于测试self.操作所产生的BUG@end实现部分
#import "OCDeomer.h"@implementation OCDeomer@synthesize img;//setter ,getter的实现-(id)init{ self = [super init]; if (self) { //init to do . UIImage* _img = [[UIImage alloc]init]; self.img = _img;//这句话很关键,如果修改为img = _img;哪么后面调用test就会CRASH,因为出了init,_img释放了。 [_img release]; } return self;}-(void)dealloc{ [super dealloc];}-(void)test{ NSLog(@"width = %f",img.size.width);}@end
分析:如果简单的将img = _img;即指向_img;但出了init方法的时候指针释放了,哪么在调用test时,这个时候img就为空指针了,当然就错了。哪为什么加上self.就正确了呢,关键就在于retain这个关键词。(assign,retain,copy)后面逐步分析。
在什么情况下self.与没有使用self.的操作时效果一样,哪就是属性使用关键词assign时。
关键词:
readwrite 读写操作,默认生成setter ,getter 方法。类似DELPHI中的property xxx:integer read getxxx write setxxxx;
readonly 只读操作。类似DELPHI中的property xxx:integer read getxxx;
assign 赋值操作,这个属性一般用来处理基础类型,比如int、float等等,如果你声明的属性是基础类型的话,assign是默认的,你可以不加这个属性。
其setter,getter 的实现:
如上例子的count属性。
-(void)setCount:(NSInteger) tcount
{
ct = tcount;//直接赋值。
}
-(NSInteger)count
{
return ct;
}
retain 引用计算+1操作(针对NSObject的对象集合);retain只是引用计数加1,但内存地址实际上只有一个,与assign 最主要的区别就在于setter方法。
-(void)setName:(NSString*) aName
{
if (name!=aName)
{
[name release];
name = [aName retain];
}
}
对于retain的属情,在dealloc 方法中,使用[变量 release];变量 = nil;的方式进行释放,但也可以使用self.变量=nil;实际是[self set变量:nil],再进到方法体内可以看到nil retain,这个操作实际上是不起作用。
copy 浅拷贝,如果要实现深考贝需要自己实现COPY方法,该关键词限定的类型必须是实现了copy 或mutablecopy。否则不能将属性设置为copy;这个会自动生成你赋值对象的克隆,相当于在内存中新生成了该对象的副本(新的内存地址),这样一来,改变赋值对象就不会改变你声明的这个成员变量。
ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。假如发送了一个没有遵守上诉两协议而发送 copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。
还要注意一点,当copy用在不可变的类型上时,效果就相当于retain,只有在可变的类型上时,才是真正意义的地址COPY。
copy 属性的setter 实现:
-(void)setName:(NSString*) aName
{
[name release];
name = [aName copy];
}
举个例子:
#import <Foundation/Foundation.h>@interface OCDeomer : NSObject{ NSString *_name; NSString *_phone;}@property (retain) NSString *name;//retain 属性@property (copy) NSString *phone;//copy 属性@end
-(void)setName:(NSString *)name{ [name retain]; [_name release]; _name = name;}-(NSString*)name{ return _name;}-(void)setPhone:(NSString *)phone{ [_phone release]; _phone = [phone copy];}-(NSString*)phone{ return _phone;}
调用:
- (IBAction)onset:(id)sender { OCDeomer* dm = [[OCDeomer alloc]init]; //NSMutableString *string = [NSMutableString stringWithString:@"Hello"];//使用这个时COPY属性才有效。 NSString *string = [[NSString alloc]initWithString:@"hello"];//不可变类型,COPY属性=retain [dm setName:string]; [dm setPhone:string]; NSLog(@"name = %@,phone = %@",dm.name,dm.phone); string = [string stringByAppendingString:@"ko"]; //[string appendString:@"world"]; NSLog(@"name = %@,phone = %@",dm.name,dm.phone); [string release]; [dm release];}
其实倒底是不是这个结论我还差点底,因为我在跟踪过程中,使用p 打印查看地址,发现不可变的字符每次在重新赋值时,地址是变化的。
为了搞懂这个COPY为地址而不是引数+1;我特写了一个例子进行演示:
#import <Foundation/Foundation.h>@interface CopyDemo : NSObject<NSCopying,NSMutableCopying>//继承NSCopying,NSMutableCopying@property (nonatomic) NSInteger age;@end
#import "CopyDemo.h"@implementation CopyDemo@synthesize age;- (id)copyWithZone:(NSZone *)zone{ CopyDemo *copy = [[[self class] allocWithZone:zone] init]; copy->age = age; return copy;}- (id)mutableCopyWithZone:(NSZone *)zone{ CopyDemo *copy = NSCopyObject(self, 0, zone); copy->age = age; return copy;}@end
演示类:
#import <Foundation/Foundation.h>#import "CopyDemo.h"@interface OCDeomer : NSObject{ CopyDemo * copydemo; CopyDemo * retainDemo;}@property (copy) CopyDemo *copydemo;//COPY 属性@property (retain) CopyDemo *retainDemo;//Retain 属性@end实现部份:#import "OCDeomer.h"@implementation OCDeomer@synthesize retainDemo;@synthesize copydemo;@end
调用测试结果:- (IBAction)onset:(id)sender { OCDeomer* dm = [[OCDeomer alloc]init]; CopyDemo * demo = [[CopyDemo alloc]init]; demo.age = 30; [dm setRetainDemo:demo]; [dm setCopydemo:demo]; NSLog(@"retain.age = %i,copy.age = %i",dm.retainDemo.age,dm.copydemo.age); demo.age = 40;//retain 的话,修改值,将会改变dm内部的值。即外部修改影响到了类的内部值。 NSLog(@"retain.age = %i,copy.age = %i",dm.retainDemo.age,dm.copydemo.age); [demo release]; [dm release];}
结果:
2013-01-27 00:00:21.304 demo[852:207] retain.age = 30,copy.age = 302013-01-27 00:00:21.307 demo[852:207] retain.age = 40,copy.age = 30
因此在实际操作过程中,对retain和copy 属性的使用需要谨慎,如果对属性设置后,不想后续的修改影响到已传给属性的值,就使用COPY,如果想外部改变影响到内部的值的变化时,就使用retain。但没有绝对的写法,只有在实际中谨用才能把质量提高。同样在dealloc中可以使用self.属性=nil来释放内存。nonatomic 非原子操作,默认情况下是原子的。
为什么验证属性的多线程操作,在设置为nonatomic,同时加入日志跟踪。
@property (nonatomic) NSInteger count;
-(void)setCount:(NSInteger) tcount
{
NSLog(@"Access in");
ct = tcount;
NSLog(@"Access out");
}于是建立一个线程进行访问NSInteger aa = 1000;
while (aa>0) {
[NSThread detachNewThreadSelector:@selector(thread1) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(thread2) toTarget:self withObject:nil];
aa--;
}-(void)thread1
{
demoer.count = 30; //demoer为全局的。
}
-(void)thread2
{
demoer.count = 40;
}结果:
2013-01-27 00:32:23.188 demo[1045:f9e03] Access in
2013-01-27 00:32:23.246 demo[1045:fb203] Access in
2013-01-27 00:32:23.250 demo[1045:ed603] Access out
2013-01-27 00:32:23.250 demo[1045:ee003] Access out
2013-01-27 00:32:23.251 demo[1045:eea03] Access out
2013-01-27 00:32:23.251 demo[1045:ef403] Access out
2013-01-27 00:32:23.149 demo[1045:f9403] Access in
2013-01-27 00:32:23.252 demo[1045:efe03] Access out
2013-01-27 00:32:23.252 demo[1045:f1203] Access out
2013-01-27 00:32:23.259 demo[1045:f0803] Access out
2013-01-27 00:32:23.260 demo[1045:f1c03] Access out
2013-01-27 00:32:23.260 demo[1045:f2603] Access out
2013-01-27 00:32:23.261 demo[1045:f3003] Access out
2013-01-27 00:32:23.261 demo[1045:f3a03] Access out
2013-01-27 00:32:23.262 demo[1045:f4403] Access out
2013-01-27 00:32:23.262 demo[1045:f5803] Access out
2013-01-27 00:32:23.263 demo[1045:f6203] Access out
2013-01-27 00:32:23.263 demo[1045:f4e03] Access out
2013-01-27 00:32:23.264 demo[1045:f7603] Access out
2013-01-27 00:32:23.265 demo[1045:f8003] Access out
2013-01-27 00:32:23.264 demo[1045:f6c03] Access out
2013-01-27 00:32:23.266 demo[1045:f8a03] Access out
2013-01-27 00:32:23.270 demo[1045:fbc03] Access in
2013-01-27 00:32:23.272 demo[1045:fb203] Access out
2013-01-27 00:32:23.271 demo[1045:f9e03] Access out
2013-01-27 00:32:23.293 demo[1045:f7607] Access in
2013-01-27 00:32:23.277 demo[1045:f9403] Access out
从上面看不是一进一出的,即多线程访问不安全的。哪好,同样我把属性改为了原子操作。即,改为
@property (automic) NSInteger count;
同样式测试,我也惊奇的发现,原来还是不安全的。
2013-01-27 02:01:45.504 demo[187:6433] Access out
2013-01-27 02:01:45.522 demo[187:6437] Access in
2013-01-27 02:01:45.531 demo[187:d86f] Access in
2013-01-27 02:01:45.539 demo[187:aa57] Access in
2013-01-27 02:01:45.542 demo[187:6437] Access out
2013-01-27 02:01:45.542 demo[187:d86f] Access out
2013-01-27 02:01:45.543 demo[187:aa57] Access out因此感觉并不像网上所说的使用原子访问时,会自动在属性访问前加上LOCK,完后UNLOCK。但经验证,并非如此。
如果有高手觉察这里有问题,请指教指教了。
总结:
assign 普通的赋值,使用self.和没有是一样的结果。
retain 引用计数+1,使用self.和没有是不一样的,有区别。
copy 地址COPY,使用self.和没有是不一样的,也是有区别的。
- IOS 的属性剖析(点语法操作)
- iOS点语法@property属性
- IOS--OC--LessonProperty 属性 点语法
- iOS开发之OC语法基础(三)--属性、点语法
- 自学iOS开发系列----OC(属性、点语法、修饰符)
- ios 视频学习 3.4 @property属性和点语法
- iOS开发学习第二十一课——属性 / 点语法
- iOS成员变量、成员属性和点语法
- 属性和点语法(16.5.9)
- 属性与点语法
- 属性,Property,点语法
- 属性以及点语法
- OC属性、点语法
- 点语法、属性
- 点语法访问属性
- 属性、点语法
- 利用Yacc生成LR语法分析器的关键点剖析
- OC 属性的属性 点语法的使用 KVC
- UVa 10006 - Carmichael Numbers
- 贪财的富翁
- 开始 继续 停止
- CMakeLists.txt文件写法
- java动态代理
- IOS 的属性剖析(点语法操作)
- 选择排序小总结。
- 如何解决 linux 操作系统显示中文乱码问题?
- android 颜色
- 结交“混世魔猴”
- 为什么负逻辑可以抗串模干扰
- POJ 1258 lightblueme Agri Net angry!89次的失误终于得到最后的成功
- JAVA代码(三)
- HTTP与HTTPS区别