@property和@synthesize:
假设我们要做5个数的加法运算(即有5个实例变量),那是否应该声明10个方法,即分别声明各个属性的设置和取得方法,这样做是不是很麻烦?幸好从OC 2.0开始,我们能让系统自动生成设置变量值的方法和获取变量的值的方法。通过这个功能,可以减少编码量,并将更多的精力放在程序的业务逻辑上,在接口文件中(也即是拓展名为.h的文件)使用@property来标示属性(一般是实例变量);在实现文件中(也即是拓展名为.m的文件)使用@synthesize标识所声明的属性,让系统自动生成设置方法和获取方法,下面通过一个例子看一下@property和@synthesize的程序:
声明文件Person.h:
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _age;
// int age;
int _height;
double _weight;
NSString *_name;
}
// @property:可以自动生成某个成员变量的setter和getter声明
@property int age;
//- (void)setAge:(int)age;
//- (int)age;
@property int height;
//- (void)setHeight:(int)height;
//- (int)height;
- (void)test;
@property double weight;
@property NSString *name;
@end
实现文件Person.m:
#import "Person.h"
@implementation Person
// @synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量
@synthesize age = _age;
@synthesize height = _height;
@synthesize weight = _weight, name = _name;
@end
类测试文件:
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Cat.h"
#import "Dog.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Dog *d = [Dog new];
d.age = 5;
NSLog(@"%d", d.age);
}
return 0;
}
定义@property的标准语法格式是:
@property (属性列表) 实例变量;
在我们的上面的例子中,属性列表没有设置任何属性
控制set方法的内存管理
retain : release旧值,retain新值(用于OC对象)
assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy : release旧值,copy新值(一般用于NSString *)
控制需不需生成set方法
readwrite :同时生成set方法和get方法(默认)
readonly :只会生成get方法
多线程管理
atomic :性能低(默认)
nonatomic :性能高
控制set方法和get方法的名称
setter : 设置set方法的名称,一定有个冒号:
getter : 设置get方法的名称
下面以Cat为例简单说明:
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Cat.h"
#import "Dog.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Dog *d = [Dog new];
d.age = 5;
NSLog(@"%d", d.age);
}
return 0;
}
cat.h:
#import <Foundation/Foundation.h>
@interface Cat : NSObject
{
//int _age;
//int age;
}
@property int age;
@end
cat.m
#import "Cat.h"
@implementation Cat
// 默认会访问age这个成员变量,如果没有age,就会自动生成@private类型的age变量
@synthesize age;
@end
@property
用在@interface中
用来自生成setter和getter的声明
用@property int age;就可以代替下面的两行
- (int)age; //getter
- (void)setAge : (int )age;//setter
@synthesize
用在@implementation中
用来自动生成setter和getter的实现
用@synthesize age = _age;就可以代替
- (int)age
{
return _age;
}
- (void )setAge : (int)age
{
_age = age;
}
@synthesize的细节
@synthesize age = _age;
setter 和getter 实现中会访问成员变量_age
如果成员变量 _age不存在,就会自动生成一个@private的成员变量_age
@synthesize age;
setter 和getter 实现中会访问成员变量_age
如果成员变量 _age不存在,就会自动生成一个@private的成员变量age
手动实现
若手动实现了setter方法,编译器就会自动生成getter方法
若手动实现了getter方法,编译器就会自动生成setter方法
若同时手动实现了setter和getter方法,编译器就不会自动生成不存在的成员变量
@property新特性:
自从Xcode4.4后,@property就独揽了@synthesize的功能,也就是说,@property可以同时生成setter和getter的声明和实现
默认情况下,setter和getter方法中的实现,会去访问下划线_开头的成员变量
#import <Foundation/Foundation.h>
@interface Dog : NSObject
@property int age;
@end
#import "Dog.h"
@implementation Dog
- (void)setAge:(int)age
{
}
//- (int)age
//{
//
//}
//- (int)age
//{
// return 10;
//}
@end
id类型:
在OC中,id类型是一个独特的数据类型。在概念上,类似于Java的Object类,可以装换为任何数据类型。换句话说,id类型的变量可以存放任何数据类型的对象。在内部处理上,这种类型被定义为指向对象的指针,实际上是一个指向这种对象的实例变量的指针。例如,下面定义了一个id类型的变量和返回一个id类型的方法:
-(id) newObject : (int) type;
id 和void *并非完全一样,下面是id在objc.h中的定义:
typedf struct objc_object
{
Class isa;
} *id;
从上面看出,id 是指向struct objc_object的一个指针。也就是说,id 是一个指向任何一个继承了Object类的对象。需要注意的是id 是一个指针,所以在使用id的时候不需要加星号,比如:
id foo = nil;
上述语句定义了一个nil指针,这个指针指向NSObject 的任意一个类,而”“id *foo = nil;”则定义了一个指针,这个指针指向另一个指针,被指向的这个指针指向NSObject的一个类。
在OC中,id 取代了int类型称为默认的数据类型,关键字nil被定义为空对象,也就是值为0的对象。
下面距离说明:
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@property id obj;
@end
Person.m
#import "Person.h"
@implementation Person
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
void test(id d)
{
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p = [Person new];
//[p fsdfdsfd];
NSObject *o = [Person new];
// id == NSObject *
// 万能指针,能指向\操作任何OC对象
id d = [Person new];
[d setAge:10];
[d setObj:@"321423432"];
NSLog(@"%d", [d age]);
}
return 0;
}