readwrite
readonly
assign
retain
copy
直接复制,用于基本数据类型(NSInteger/CGFloat), C数据类型(int, float, double, char), 还有 id
类型
不涉及内存管理,当 assign
修饰对象类型是,会导致内存泄漏或 EXC_BAD_ACCESS
虽然 assign
与 weak
的含义接近,但 assign
一般修饰基本数据类型,weak
修饰对象类型,当 weak
修饰对象类型是,当对象被释放后,weak
会将变量自动置 nil
, 而 assign
修饰时,变量的对象地址并不会发生变化,但对象却已经被释放了
当对 assign
修饰的对象进行复制时,编译器也会发生警告
针对对象类型进行内存管理,对基本数据类型使用会报错
同时,ARC 下已经不需要使用 retain
主要用于 NSString
类型,用于复制内容,复制行为取决于 - (id)copyWithZone:(NSZone *)zone
的实现
atomic
nonatomic
线程保护技术,保护变量读取安全,但缺点是浪费系统资源,因此在运行 iOS 的小型设备上,一般使用 nonatomic
而对于需要多线程安全的场景,一般使用 nonatomic
修饰符,并在执行代码中,使用 NSLock
等手动加锁的方法来保证安全
但使用 atomic
之后,所修饰的数据就一定线程安全吗?
不是
线程安全的安全,实际上是指在多线程的情况下,访问同一个数据(内存位置),获得的结果符合预期
而
atomic
只能保证属性的getter
或setter
中线程安全,并不是getter
与setter
都线程安全 这意味着,当有 A, B 两个线程同时去访问属性 c. A 对 c 进行了写入操作,而后在对 c 进行读取操作,B 也对 c 进行了写操作。而我们预期的结果是:A 对 c 读取的结果应该是 A 对 c 写入的值而此时我们只使用了
atomic
来修饰,那么,A 对 c 的写操作是安全的(写入 1),但之后 B 立刻也对 c 进行了写操作(写入 2),实际上这个写操作也是线程安全的。最后 A 才对 c 进行读取,读取到了 2, 而不是我们希望的 1, 此时,就说线程不安全了 而要保证 A 对 c 的写入和读取操作统一,就需要利用额外的锁机制来保证,如NSLock
用于设置自定义 property 的 getter, setter 方法
基本数据类型 atomic
+ readwrite
+ assign
Objective-C 对象 atomic
+ readwrite
+ strong
@property = ivar + getter + setter
@interface AnObject: NSObject
@property NSString *name;
@end
等价于
@interface AnObject: NSObject
- (NSString *)name;
- (void)setName:(NSString *)name;
@end
@implementation AnObejct
@synthesize name = _name; // _name 为中间变量
- (NSString *)name {
// ...
}
- (void)setName:(NSString *)name {
// ...
}
@end
在 Runtime 中,propery 的定义是
typedef struct objc_property *objc_property_t;
而 objc_property
的定义又是
struct property_t {
const char *name;
const char *attributes;
};
而 attributes
虽然看起来是 char *
, 但是它的结构又是
/// Defines a property attribute
typedef struct {
const char *name; // 属性名称
const char *value; // 属性的修饰符,类型
} objc_property_attribute_t;
可以通过 property_getAttributes 获取到 attributes