美文网首页Objective-C
成员变量与属性

成员变量与属性

作者: 码小菜 | 来源:发表于2019-04-19 12:31 被阅读3次

目录
一,基本概念
二,成员变量
三,属性
 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
外部访问.png

三,属性

  • 本质

@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
  • 默认关键字

基本数据类型:atomicreadwriteassign
对象类型:atomicreadwritestrong

@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

unsafe_unretained.png

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,用于NSStringBlock等类型,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];

相关文章

  • iOS复习之成员变量、成员属性

    复习下两种语言成员变量和成员属性如何创建 iOS 开发中成员变量与属性的区别iOS开发 -- 属性与成员变量 关于...

  • iOS 基础知识总结 更新中...

    属性 属性与成员变量之间的关系 属性对成员变量扩充了存储方法 属性默认会生成带下划线的成员变量 声明了成员变量不会...

  • iOS 对属性变量setter和getter方法的理解

    关于成员变量、实例变量、属性变量 成员变量 成员变量是用于类的内部,无需与外界接触的变量。成员变量默认是prote...

  • iOS 对属性变量setter和getter方法的理解

    关于成员变量、实例变量、属性变量 成员变量 成员变量是用于类的内部,无需与外界接触的变量。成员变量默认是prote...

  • iOS 对属性变量setter和getter方法的理解

    关于成员变量、实例变量、属性变量 成员变量 成员变量是用于类的内部,无需与外界接触的变量。成员变量默认是prote...

  • 成员变量与属性

    写完类与对象后,我们今天来讲讲成员变量和属性。 1.类型编码 编译器将每个方法的返回值和参数类型编码为一个字...

  • 属性与成员变量

    成员变量是类内部的变量, 外部类不能直接访问该变量! @interface MyViewController :U...

  • 成员变量与属性

    成员变量是定义在{}号中的变量,如果变量的数据类型是一个类则称这个变量为实例变量。因为实例变量是成员变量的一种特殊...

  • 成员变量与属性

    目录一,基本概念二,成员变量三,属性 1,本质 2,默认关键字 3,atomic,nonatomic 4,read...

  • 剖析成员变量与属性变量@property/@synthesis/

    iOS中属性与成员变量的区别 iOS开发日记-2014.6.20 成员变量、实例变量、属性之间的关系 在 iOS5...

网友评论

    本文标题:成员变量与属性

    本文链接:https://www.haomeiwen.com/subject/suiqwqtx.html