重学OC第五篇:属性关键字、方法归属、内省

一、属性关键字

1 @property、@synthesize 和 @dynamic

@interface TestA : NSObject

@property() NSString *name;
@property() NSString *synthesizeName;
@property() NSString *dynamicName;

@end

@implementation TestA
@synthesize synthesizeName = customName;
@dynamic dynamicName;

@end

用clang -rewrite-objc main.m转为c++

struct TestA_IMPL {
   
   
	struct NSObject_IMPL NSObject_IVARS;
	NSString *customName;
	NSString *_name;
};
// @property() NSString *name;
// @property() NSString *synthesizeName;
// @property() NSString *dynamicName;
/* @end */
// @implementation TestA
// @synthesize synthesizeName = customName;
static NSString * _I_TestA_synthesizeName(TestA * self, SEL _cmd) {
   
    return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$customName)); }
static void _I_TestA_setSynthesizeName_(TestA * self, SEL _cmd, NSString *synthesizeName) {
   
    (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$customName)) = synthesizeName; }

// @dynamic dynamicName;
static NSString * _I_TestA_name(TestA * self, SEL _cmd) {
   
    return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)); }
static void _I_TestA_setName_(TestA * self, SEL _cmd, NSString *name) {
   
    (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)) = name; }
// @end
  • @property会变为getter、setter方法的声明,与之对应的一个是@synthesize,一个是@dynamic;
  • @synthesize由编译器合成getter、setter方法的实现,也会合成带下划线的成员变量;
    不自动合成的情况:
    • 同时重写了 setter 和 getter 时
    • 重写了只读属性的 getter 时
    • 使用了 @dynamic 时
    • 在 @protocol 中定义的所有属性
    • 在 category 中定义的所有属性
    • 重载的属性
  • @dynamic由用户自己去实现getter、setter方法和需要的成员变量。

具体请参考官方文档: Encapsulating Data

2 nonatomic、atomic

  • atomic是表示属性原子性,范围仅限于setter方法内,属性原子性不是对象线程安全的同义词。默认为atomic。
  • nonatomic就是非原子性。

3 readwrite、readonly

  • readwrite就是要生成或自己实现get和set方法, 默认是readwrite。
  • readonly只要求生成或自己实现get方法。

4 strong、retain、weak、assign、copy、unsafe_unretained

  • strong ARC下默认,引用计数+1
  • retain ARC下一般用strong,引用计数+1
  • weak 一般用于避开循环引用,对象释放会自动置为nil,引用计数不变
  • assign 基本类型的默认修饰符,也可以用于对象,引用计数不变,不会置nil
  • copy 不可变对象是浅拷贝, 可变对象是深拷贝,返回的都为不可变对象
  • unsafe_unretained 只能用于对象,引用计数不变,不会置nil,会变为野指针

5 nullable、nonnull

  • nullable就是指针可为nil
  • nonnull就是指针不可为nil。这两个都不是默认的,需要显式指出。

6 属性修饰符分析

6.1 objc_getProperty与objc_setProperty

@interface TestA : NSObject

@property(nonatomic) NSString *name;
@property(atomic) NSString *name1;
@property(copy) NSString *name2;
@property(nonatomic, copy) NSString *name3;

@end

@implementation TestA

@end

转为c++

static NSString * _I_TestA_name(TestA * self, SEL _cmd) {
   
    return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)); }
static void _I_TestA_setName_(TestA * self, SEL _cmd, NSString *name) {
   
    (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name)) = name; }

static NSString * _I_TestA_name1(TestA * self, SEL _cmd) {
   
    return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name1)); }
static void _I_TestA_setName1_(TestA * self, SEL _cmd, NSString *name1) {
   
    (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name1)) = name1; }

extern "C" __declspec(dllimport) id objc_getProperty(id, SEL, long, bool);

static NSString * _I_TestA_name2(TestA * self, SEL _cmd) {
   
    typedef NSString * _TYPE;
return (_TYPE)objc_getProperty(self, _cmd, __OFFSETOFIVAR__(struct TestA, _name2), 1); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_TestA_setName2_(TestA * self, SEL _cmd, NSString *name2) {
   
    objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestA, _name2), (id)name2, 1, 1); }

static NSString * _I_TestA_name3(TestA * self, SEL _cmd) {
   
    return (*(NSString **)((char *)self + OBJC_IVAR_$_TestA$_name3)); }
static void _I_TestA_setName3_(TestA * self, SEL _cmd, NSString *name3) {
   
    objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestA
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值