目录
一,基本概念
二,成员变量
三,属性
1,本质
2,默认关键字
3,atomic,nonatomic
4,readonly,readwrite
5,assign
6,弱(unsafe_unretained,weak)
7,强(retain,strong)
8,copy
9,getter,setter
10,class
11,nonnull,nullable,null_unspecified,null_resettable
12,@synthesize,@dynamic
13,带双下划线的关键字
一,基本概念
1,{}
内的都是成员变量(_name
,_sex
,_age
)
2,对象类型的成员变量是实例变量(_name
,_sex
)
3,@property
修饰的是属性(name
)
@interface Person : NSObject
{
NSString *_name;
id _sex;
NSInteger _age;
}
@property (nonatomic, copy) NSString *name;
@end
二,成员变量
-
访问方式
// 内部
_name = @"111";
self -> _name = @"111";
// 外部
Person *p = [Person new];
p -> _name = @"111";
-
访问权限
@private
:当前类可以访问
@protected
:当前类及其子类可以访问
@package
:同一个包下可以访问
@public
:任何地方都可以访问
1,在.h文件中定义的遵循如上权限(默认为@protected
)
2,在.m文件中定义的,无论用什么修饰符,都是@private
权限
// .h文件
@interface Person : NSObject
{
@private
NSString *_name1;
@protected
NSString *_name2;
@package
NSString *_name3;
@public
NSString *_name4;
}
@end
// .m文件
@implementation Person
{
@private
NSString *_name5;
@protected
NSString *_name6;
@package
NSString *_name7;
@public
NSString *_name8;
}
@end

三,属性
-
本质
@property = ivar + getter + setter
ivar
:带下划线的成员变量,用于保存数据
getter
:get方法,获取成员变量的值
setter
:set方法,设置成员变量的值
// .h文件
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
// .m文件
@implementation Person
// 带下划线的成员变量
@synthesize name = _name;
// get方法
- (NSString *)name {
return _name;
}
// set方法
- (void)setName:(NSString *)name {
_name = name;
}
@end
-
默认关键字
基本数据类型:atomic
,readwrite
,assign
对象类型:atomic
,readwrite
,strong
@property NSString *name;
-
atomic,nonatomic
atomic
:原子的,会为set方法加锁
nonatomic
:非原子的,不加锁
加锁虽然能保证线程安全,但同时也会消耗资源,所以非需抢占资源的属性都声明为nonatomic
- (void)setName:(NSString *)name {
@synchronized (self) {
_name = name;
}
}
-
readonly,readwrite
readonly
:只生成get方法,可以获取成员变量,但不可以设置
readwirte
:生成get/set方法,可以获取成员变量,也可以设置
-
assign
1,用于基本数据类型,set方法里直接赋值,引用计数不变
- (void)setAge:(NSInteger)age {
if (_age != age) {
_age = age;
}
}
2,为什么不能修饰对象?
答:
1,基本数据类型的内存被分配在栈上,由系统分配释放;对象的内存被分配在堆上,由程序员分配释放
2,如果用assign修饰对象,当对象被释放后,指针的地址还存在,指针没有被置为nil,从而造成了野指针,如果在后续的内存分配中,刚好用到了这块内存,就会出现crash
3,基本数据类型在栈上,系统会把指针置为nil,不会造成野指针
-
弱(unsafe_unretained,weak)
1,unsafe_unretained
:当对象销毁后不会自动被置为nil,会引起野指针crash,所以一般用weak

2,weak
:当对象销毁后会自动被置为nil,不会出现野指针,用于Delegate
等类型,引用计数不变
// 防止循环引用
@property (nonatomic, weak) id<ViewControllerDelegate> delegate;
// 在xib中已经被self.view强引用了,self无需再对它强引用
@property (nonatomic, weak) IBOutlet UIButton *button;
// 已经被self.view强引用了,self无需再对它强引用
@interface ViewController ()
@property (nonatomic, weak) UIButton *button;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn = [UIButton new];
[self.view addSubview:btn];
self.button = btn;
}
@end
-
强(retain,strong)
retain
:用于一般对象类型,set方法里release旧值retain新值,引用计数+1(MRC下使用)
strong
:代替retain
(ARC下使用)
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name retain];
}
}
-
copy
1,用于NSString
,Block
等类型,set方法里release旧值copy新值,NSString引用计数+1,NSMutableString引用计数不变
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name copy];
}
}
2,NSString为什么用copy修饰?
答:
1,NSString + copy = NSString,浅拷贝,源NSString引用计数+1,对于NSString用copy或strong修饰都一样
2,NSMutableString + copy = NSString,深拷贝,NSMutableString引用计数不变,NSString引用计数为1,如果NSMutableString被修改了也不会影响到NSString,这就是用copy修饰的原因
NSString *str1 = @"111";
NSString *str2 = str1.copy;
NSLog(@"str1: %p, str2: %p", str1, str2);
// 打印结果
str1: 0x10f6ad078, str2: 0x10f6ad078
NSMutableString *str1 = [NSMutableString stringWithString:@"111"];
NSString *str2 = str1.copy;
NSLog(@"str1: %p, str2: %p", str1, str2);
// 打印结果
str1: 0x600001b2d140, str2: 0xbfdf7f0c3b6800ca
-
getter,setter
getter
:设置get方法名称
setter
:设置set方法名称
@property (nonatomic, copy) NSString *name;
// 默认方法名
- (NSString *)name {}
- (void)setName:(NSString *)name {}
@property (nonatomic, copy, getter=getName, setter=settingName:) NSString *name;
- (NSString *)getName {}
- (void)settingName:(NSString *)name {}
-
class
用class
修饰的属性是类属性,直接用类访问即可
@interface Person : NSObject
@property (nonatomic, copy) NSString *name1;
@property (nonatomic, copy, class) NSString *name2;
@end
@implementation Person
- (NSString *)name1 {
return @"111";
}
+ (NSString *)name2 {
return @"222";
}
@end
NSLog(@"name1---%@", Person.new.name1);
NSLog(@"name2---%@", Person.name2);
// 打印结果
name1---111
name2---222
-
nonnull,nullable,null_unspecified,null_resettable
nonnull
:不能为空
nullable
:可以为空
null_unspecified
:不确定是否为空
null_resettable
:get方法不能返回空,set方法可以设置为空(需要重写get或set方法来处理值为空的情况)
@property (nonatomic, copy, null_resettable) NSString *name;
- (NSString *)name {
if (_name == nil) {
_name = @"111";
}
return _name;
}
- (void)setName:(NSString *)name {
if (name == nil) {
name = @"111";
}
_name = name;
}
-
@synthesize,@dynamic
@synthesize
:
1,表示如果没有手动实现get/set方法,编译器会自动生成这两个方法
2,默认就是@syntheszie ivar = _ivar;
,一般不用显示声明
3,如果get/set方法都手动实现了,就必须显示声明
@implementation Person
@synthesize name = _name;
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
@end
@dynamic
:
1,表示get/set方法都需要手动实现,编译器不会自动生成
2,如果声明了@dynamic ivar;
,就必须手动实现get/set方法,否则使用该属性时会crash
@interface Person ()
{
NSString *_name;
}
@end
@implementation Person
@dynamic name;
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
@end
-
带双下划线的关键字
__unsafe_unretained
,__weak
,__strong
,__nonnull
,__nullable
,__null_unspecified
与不带下划线的关键字含义相同,只是用法不同
__strong Person *p = [Person new];
网友评论