ios-属性修饰符

常用属性修饰符
// 成员变量 只能在自己类内部使用的 (自己的.m中使用)
@interface someObject : NSObject { 
	NSString *firstName; // 成员变量 私有
}

@property (nonatomic, copy) NSString *lastName; // 属性 默认 public
@property (nonatomic, unsafe_unretained)
@property (nonatomic, assign) // 修饰基础变量 int  bool 等
  
// MRC 时使用 retain  
@property (nonatomic, retain) // 会使引用计数加1

// ARC 后使用 weak strong  
@property (nonatomic, weak) // 若引用
@property (nonatomic, strong) // 强引用

@end    
复制代码
// someObject.m 文件

@interface someObject ()
@property (nonatomic, copy) NSString *name; // 属性 默认 private
@end
  
@implementation someObject
  
@end  

复制代码
默认行为

nonatomicatomic 中默认 atomic

@property (assign) int age;
相当于
@property (nonatomic, assign) int age;
复制代码

strongassignweakcopy 中默认 assign

@property (nonatomic) int age;
相当于
@property (nonatomic, assign) int age;
复制代码
@property 的本质
@property = ivar + getter + setter;
// 实例变量(成员变量) + getter方法 + setter方法
// 默认的成员变量为 在变量名前加下划线_ 
复制代码

我们把@property修饰的变量称为属性(相对于成员变量,最上面的代码有注释),其默认实现了getter,setter方法,使得我们可以使用.(点语法)来访问

setter getter 方法

@property (nonatomic, copy) NSString *name; // 默认生成成员变量 _name
复制代码

对于成员变量name,set方法的格式是setName,get方法的格式只是直接使用属性名name

@property (nonatomic,copy) NSString *name;

// 可自己实现 set  或 get 方法,两个都实现就必须实现下面这行,否则报错
// 因为你重写了set 和 get 方法后,系统就不会实现synthesize,相当于没有声明 _name 成员变量
@synthesize name = _name;

- (NSString *)name{
    if (!_name) {
        _name = @"";
    }
    return _name;
}

- (void)setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name copy]; // 这是面试时优化的点 [name retain] 同时不能使用.语法,.语法默认会调用setName方法,从而形成递归调用,造成崩溃
    }
}
复制代码

定义一个@property,在编译期间,编译器会生成实例变量、getter方法、setter方法,这些方法、变量是通过自动合成(autosynthesize)的方式生成并添加到类中。实际上,一个类经过编译后,会生成变量列表ivar_list,方法列表method_list,每添加一个属性,在变量列表ivar_list会添加对应的变量,如_name,方法列表method_list中会添加对应的setter方法和getter方法。

. 语法
self.name = @"dog";
复制代码

会调用getter方法获取_name,然后调用setter方法进行赋值。

所以如果在setter方法中通过. 语法进行赋值将会出现递归调用setter方法,导致崩溃

原子

atomic:原子属性,为setter方法加自旋锁(即为单写多读)

- (void)setObj2:(NSObject *)obj2{ 
    //加锁
    @synchronized(self) {
        _obj2 = obj2;
    }
}  

复制代码

从代码中可以看到,atomic只能保证setter,getter方法内部的线程安全,而且只能保证在单独调用setter或getter方法时是线程安全的,这就有很大的隐患。假设有一个线程A在不断的读取属性name的值,同时有一个线程B修改了属性name的值,那么即使属性name是atomic,线程A读到的仍旧是修改后的值,可见不是线程安全的。如果想要实现线程安全,需要手动的实现锁。

引申一下:在64位操作系统中,一个cpu寻址就是8个字节,int占4个字节,所以对于int,无论是不是原子操作,其本身都是原子操作。long double 分别占8个字节,理论上也是原子操作的。对一个long型数据的读写,操作系统有可能分两部分进行,一部分是高位,一部分是低位,所以两个线程同时操作long数据,有可能导致数据不同步,但实际应该很少发生,因为太快了。再说 double,double 类型的数据同样占8个字节,按道理来说,他读写的速度应当和long 一样快。但是。一个线程读写内存仅仅只是一个方面,cpu 需要对数据进行计算,这个计算的中间结果一般都会放到寄存器或者cpu 高速缓存,double 数据计算的复杂度远非long型所能比,因此double 数据类型相比long 型数据更容易出现并发的问题。

assign

assign修饰的修饰基本数据类型分配在栈上,栈上空间的分配和回收都是系统来处理的,因此开发者无需关注,也就不会产生野指针的问题。

而assign修饰的对象类型数据和weak修饰的对象类型数据一样分配在堆中。如果assing修饰对象释放后,其指针将称为野指针。

weak

weak是ARC的产物,主要作用是修饰若引用的对象,防止循环引用。

@property (nonatomic, weak) id objc;

复制代码

weak具有如此功能的原因是在weak修饰的objc被销毁时,会主动在objcdealloc方法中将所有用weak修饰的指向objc的指针置为nil

简单理解如下,具体执行过程还要参考内存方面的文章

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。 weak表其实是一个hash(哈希)表,Key是所指对象的地址,Valueweak指针的地址数组。 当A对象销毁时.以A的内存地址为Key, 在这个 weak 表中搜索

delegate 用assign还weak?

assign属性一般是对C基本数据类型成员变量的声明,当然也可以用在对象类型成员变量上,只是其代表的意义只是单纯地拷贝所赋值变量的指针。即如果对某assign成员变量B赋值某对象A的指针,则此B只是简单地保存此指针的值,且并不持有对象A,也就意味着如果A被销毁,则B就指向了一个已经被销毁的对象,如果再对其发送消息会引发崩溃。

MRC 时用 assign 修饰 delegate 但是要在dealloc中主动将其置为nil

@interface someObject ()
  
@property (nonatomic, assign) id <someDelegate> delegate;

@end
  
@implementation someObject 
  
- (void)dealloc {
		_delegate = nil;  
}  
  
@end  

复制代码

ARC 后直接使用weak进行修饰,并且不用将其置为nil

unsafe_unretained

和assign类似,但是它适用于对象类型,当目标被摧毁时,属性值不会自动清空(unsafe)。这是和weak的区别

@property (nonatomic, unsafe_unretained)  TestObj *s2;

复制代码
protocol 中的属性声明
@property (nonatomic, strong) NSString *name;

复制代码

不自动生成getter setter,表明实现此协议的类必须自己声明NSString *name 不声明也可以写self.name,但当调用settergetter方法时会因为找不到方法而崩溃 即使自己不添加属性NSString *name,而只添加settergetter方法,你会发现,setter方法无法写,因为没有ivar,你调用不了_name

category 中的属性声明
@property (nonatomic, strong) NSString *name;

复制代码

不自动生成getter setter, 自己无法写setter方法,因为没有ivar,你调用不了_name

转载于:https://juejin.im/post/5cb91881f265da03ae74bdb3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值