在前面的小程序中,我们会发现有这样的编码方式:
@property (nonatomic,copy)NSString * name;在这一节中,将会带领大家学习一下OC声明属性的几种方式以及怎么调用它们。
首先,我们要知道这段代码的作用是声明一个属性。在OC,先后有三种声明属性的方式:
方式1:直接在@interface中的大括号中声明
@interface Person : NSObject{
NSString * name;
}
@end
方式2:在@interface中声明,然后在@property中声明,随后在.m文件中加入 @synthesize name=_name;。.h文件中:
@interface Person : NSObject{
NSString * _name;//编写习惯,一般声明成员变量的时候名字前面加“_”
}
@property (nonatomic,copy)NSString * name;
@end
.m文件中:
@implementation Person
@synthesize name=_name;
@end
方式3:用@property中声明。
@interface Person : NSObject
@property (nonatomic,copy)NSString * name;
@end
这三种方式各有什么不同?
首先对比一下方式一和方式三:
方式一声明的name是成员变量,只能在类内部使用,不能在外部调用。
方式三声明的name可以从类外部被本类对象通过:对象.name的方式来调用。
在说一下方式二,这种写法是一种过时的声明变量的方式,Xcode在早期使用这种方式,它的效果和方式三是一样的,也有不同。虽然它相比于方式三看起来要麻烦,但是它的代码表达的很清楚。
首先声明一个成员变量_name,
@property (nonatomic,copy)NSString * name;这句的意思是为name声明并实现set和get方法(和点语法有关,后面会介绍)。
@synthesize name=_name;.m文件中的这一句将_name 赋值给了name属性,将两者进行了关联。
所以对于方式二这种编码方式,我们叫它:显式创建。
而对于方式三来说:@property (nonatomic,copy)NSString * name;
在这句代码的背后,做了这样几个工作:
首先隐式声明了一个成员变量_name,
然后内部声明并实现了name属性的set和get方法。
所以方式三被称作:隐式创建。
学到这,我们可能会有疑问,set和get方法是什么?它们和点语法有什么关系呢?下面我们一起来了解一下。
在OC编写代码中,我们采用点的方式来调用对象中的属性,或给属性赋值,或取出该属性的值。那么它到底是怎么实现的呢?这就跟OC的点语法相关。
由于OC本身是面向对象的,而面向对象的主要表现就是类这种数据类型,所以,学习OC,就少不了要和类打交道。
在使用类时,我们最多的就是使用类中的属性和方法,在对类中的属性进行操作之前,首先我们要获得它,那么就要用到我们的点语法。所以,在OC编程中,我认为点语法的学习是非常重要的,就像是人必须要吃饭一样。
在OC中,点语法的具体表现形式就是:对象.属性。我们知道了点语法的写法,可是它是怎么帮我们获取到属性的值的呢?我们学习一下。
其实,当我们通过写对象.属性来调取属性值的时候,OC帮我们调取了两个方法:set方法和get方法。
set方法是属性进行赋值时调用的方法,例如:
people.name=@"ZhangSan";
在执行这段代码的时候,OC判断出来了这时赋值语句,所以它调用了属性的set方法,将ZhangSan这个字符串赋值给了people对象的name属性,也可以这么说,这句代码在执行的时候改变成了:
[people setName:@”ZhangSan”];
这是setName:的调用,方法中含有一个字符串型的形参。
set方法的具体实现:
-(void)setName:(NSString *)name{
_name=name;
}
get方法获取属性时调用的方法,例如:
NSString * theName=people.name;
这段代码实现的功能时将people对象的name属性赋值给theName字符串。
在执行这段代码的时候,OC判断出来了这是取值操作,所以它调用了属性的get方法,将people对象的name属性取了出来。同样,它在执行的时候改变成了:
NSString * theName=[people getName];
先把name属性值取出来,然后进行赋值。
get方法的具体实现:
-(NSString *)name{
return _name;
}
那有朋友可能要问了,OC是怎么自己判断出来的呢,其实有这样一个规律可循:
在没有等号的情况下,默认是get方法。
在有等号的情况下,我们就要分两种情况:
在等号左边是set方法。
在等号右边是get方法。
学到这里,可能还有这样的疑问?我的类中没有显式set方法和get方法,它怎么会调用呢?
这就和我们前边提到的三种方式有关,方式一的这种写法没有自动产生该成员变量的set和get属性。
方式二在@property的时候,自动为该name属性添加了set 和get方法,只不过和其他代码集成在一起了。
对于编程来说,只有你想不到,没有你动手做不到的,如果你想要自己创建set和get方法,这也是可行的。
对于方式一来说,如果想通过使用set和get的形式对name进行访问,就需要自己创建set和get方法,而且必须是在.h中声明,在.m中实现,如果只在.m中实现而不在.h中声明也是不行,因为这种方式本身就没有set和get方法,本来就不能通过对象.属性的方式访问。
而对于方式三来说,就不需要这么麻烦。由于两种方式都已经隐式创建好了set和get方法。虽然我们无法让它们显示出来,但是我们可以重写set或get方法,也就是将隐藏的set或get方法覆盖。(在Xcode中编写的时候,对于重写的方法,我们只需要打“-setName”或“-name”,Xcode就给我们给我们提示,直接回车就可以了,非常方便)。
注意:方式三由于已经隐式创建好了set和get方法,所以如果我们同时重写了set和get方法,与@property声明的成员属性就不是一个成员属性了,是另外一个实例变量,而这个实例变量需要手动声明,就变成了方式二 。在实际开发过程中,要视情况而定。
对于方法二来说,由于声明了一个_name成员变量
@property (nonatomic,copy)NSString * name;相当于声明了name属性的set和get方法。
@synthesize name=_name;相当于在.m文件中对set和get方法进行实现
这一系列操作叫做:显式创建,在这种方式的前提下,我们可以同时对name属性进行set和get方法的重写而不会出错。
总结三种方式:
通过这一节的学习,你应该能过解决下面的问题: