iOS类属性探索

1.Type Encodings​​​​​​​

Student.h
@property(nonatomic,strong)NSString*nameniu
Student.m
-(void)setNameniu:(NSString *)nameniu{
}
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc  -fobjc-arc -fobjc-runtime=ios-8.0.0 Student.m
{(struct objc_selector *)"setNameniu:", "v24@0:8@16", (void *)_I_Student_setNameniu_},
static void _I_Student_setNameniu_(Student * self, SEL _cmd, NSString * _Nonnull nameniu)

v24@0:8@16分析:

v:返回值类型,void

24:参数类型的长度。

@:0长度0-7,Student * 

::8,8-15,SEL

@:16,16-23,NSString *

NSLog(@"char--%s",@encode(char)); //char--c
NSLog(@"short--%s",@encode(short));//short--s
NSLog(@"int--%s",@encode(int));//int--i
NSLog(@"long--%s",@encode(long));//long--q
NSLog(@"long long--%s",@encode(long long));//long long--q
NSLog(@"unsigned char--%s",@encode(unsigned char));//unsigned char--C
NSLog(@"unsigned short--%s",@encode(unsigned short));// unsigned short--S
NSLog(@"unsigned int--%s",@encode(unsigned int));//unsigned int--I
NSLog(@"unsigned long--%s",@encode(unsigned long));//unsigned long--Q
NSLog(@"float--%s",@encode(float));//float--f
NSLog(@"BOOL--%s",@encode(BOOL));//BOOL--c
NSLog(@"void--%s",@encode(void));//void--v
NSLog(@"char *--%s",@encode(char *));//char *--*
NSLog(@"id--%s",@encode(id));//id--@
NSLog(@"Class--%s",@encode(Class));// Class--#
NSLog(@"SEL--%s",@encode(SEL));//SEL--:
int array[] = {1,2};///
NSLog(@"int[]--%s",@encode(typeof(array)));//int[]--[2i]
typedef struct person{
    int age;
    NSString *name;
}Person;
NSLog(@"struct--%s",@encode(Person));//struct--{person=i@}

typedef union teacher{
    char *a;
    BOOL b;
}Teacher;
NSLog(@"union--%s",@encode(Teacher));//union--(teacher=*c)

static struct /*_prop_list_t*/ {
	unsigned int entsize;  // sizeof(struct _prop_t)
	unsigned int count_of_properties;
	struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_Student __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_prop_t),
	1,
	{{"nameniu","T@\"NSString\",&,N,V_nameniu"}}
};

T: type

@: 变量类型

C: copy

N: nonatomic

V: variable 变量,即下划线变量 _nameniu

2.属性

Student.h
@interface Student (){
    NSString *nameniu ; // 成员变量, 实例变量
    int age;   // 成员变量, 基本数据类型变量
    id data;   // 成员变量, 实例变量
}
@property (nonatomic, strong) NSString *sex;  //属性
@end

2.1 实例变量

如果成员变量是一个类(类的实例化), 则这个变量为实例变量, 例如上面例子name, data (id 是 OC特有的类型。从本质上讲, id 等同于 (void *))都是实例变量, 而age是int型, 是基础数据类型变量

2.2 成员变量

通常在.h/.m文件@interface以{ } 形式定义的变量

成员变量 = { 实例变量 , 基础数据类型变量 }

2.3 属性

基础类和扩展 @property = ivar + getter(声明+实现) + setter(声明+实现);

协议和分类  @property =getter(声明) + setter(声明);

编译器会自动为属性生成set, get方法, 以及生成成员变量_sex(即成员变量名前加下划线)

属性是用于与其他对象交互的变量, 正因为要与其他对象交互, 就有了属性修饰符或者叫属性特质, 如:nonatomic, readwrite, copy 等等

通过@interface XXXX {}定义的成员变量,会存储在类的bits属性中,通过bits --> data() -->ro() --> ivars获取成员变量列表,除了包括成员变量,还包括属性的成员变量

通过@property定义的属性,也会存储在bits属性中,通过bits --> data() --> properties() --> list获取属性列表,其中只包含property属性

4. objc_class的结构 

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits; 
    ...
}

isa和superclass本质都是指针类型,占用8个字节,而cache_t占用16个字节的空间,所以objc_class地址偏移32个字节的大小,就可以得到bits的地址。

可用objc源码或者自定义struct objc_class : objc_object和  class_data_bits_t  做强制转换来查看bits

(lldb) x/4gx  stu(实例对象)
0x100504640: 0x011d800100008195 0x0000000000000000
0x100504650: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x011d800100008195&0x00007ffffffffff8ULL(实例对象ISA算出类对象地址)
(unsigned long long) $1 = 0x0000000100008190
(lldb) po $1
Student
(lldb) x/4gx $1
0x100008190: 0x0000000100008168 0x00007fff88a88d88
0x1000081a0: 0x000000010065b1c0 0x0001801c00000007

也可以直接查看类对象地址
(lldb) p/x Student.class
(Class) $4 = 0x0000000100008190 Student
(lldb) x/4gx 0x0000000100008190
0x100008190: 0x0000000100008168 0x00007fff88a88d88
0x1000081a0: 0x000000010065b1c0 0x0001801c00000007

获取bits地址
(lldb) p/x 0x0000000100008190 + 0x20(32)
(long) $6 = 0x00000001000081b0

转化为class_data_bits_t
(lldb) p (class_data_bits_t *)$6
(class_data_bits_t *) $7 = 0x00000001000081b0
通过data()获取bits
(lldb) p $7->data()
(class_rw_t *) $8 = 0x0000000100862150
类似这样可以找到ro、methods、properties和protocols

使用如下方法

//获取属性列表
NSMutableArray*list= [NSMutableArray array];
unsigned int count;
objc_property_t *propertyList = class_copyPropertyList([Student class], &count);
for (unsigned int i=0; i<count; i++) {
   //const char *propertyName1 =property_getAttributes(propertyList[i]);
   const char *propertyName = property_getName(propertyList[i]);
   [list addObject:[NSString stringWithUTF8String:propertyName]];
}
NSLog(@"property----="">%@", list);
[list removeAllObjects];
//获取方法列表
Method *methodList = class_copyMethodList([Student class], &count);
for (unsigned int i; i<count; i++) {
   Method method = methodList[i];
   [list addObject:NSStringFromSelector(method_getName(method))];
}
NSLog(@"method----="">%@",list);
[list removeAllObjects];
//获取成员变量列表
Ivar *ivarList = class_copyIvarList([Student class], &count);
for (unsigned int i; i<count; i++) {
   Ivar myIvar = ivarList[i];
   const char *ivarName = ivar_getName(myIvar);
   [list addObject:[NSString stringWithUTF8String:ivarName]];
}
NSLog(@"ivar----="">%@",list);
[list removeAllObjects];
//获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([Student class], &count);
for (unsigned int i; i<count; i++) {
   Protocol *myProtocal = protocolList[i];
   const char *protocolName = protocol_getName(myProtocal);
   [list addObject:[NSString stringWithUTF8String:protocolName]];
}
NSLog(@"protocol----="">%@", list);

 1.协议属性声明

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end
@interface Student : NSObject<Student>
@end
Student.m
@implementation Student
@end

property----=>(
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
method----=>(
)
 ivar----=>(
)
protocol----=>(
    Student
)

2.协议属性声明+实现

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end
@interface Student : NSObject<Student>
@end
Student.m
@implementation Student
@synthesize nameniu = _nameniu;
@end

property----=>(
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
 ivar----=>(
    "_nameniu"
)
 protocol----=>(
    Student
)

3.协议属性声明+实现

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end
@interface Student : NSObject<Student>
@property(nonatomic,strong)NSString*nameniu;
@end
Student.m
@implementation Student
@end
property----=>(
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
ivar----=>(
    "_nameniu"
)
protocol----=>(
    Student
)

4.协议属性声明+实现

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end
@interface Student : NSObject<Student>
@property(nonatomic,strong)NSString*nameniu;
@end
Student.m
@implementation Student
@synthesize nameniu = _nameniu;
@end
 property----=>(
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
 ivar----=>(
    "_nameniu"
)
protocol----=>(
    Student
)

5.分类属性声明

Student.h
@interface Student : NSObject
@end
Student.m
@implementation Student
@end

Student+Niu.h
@interface Student (Niu)
//只有name的set跟get方法声明,没有实现,也没有生成成员变量
@property(nonatomic,strong) NSString*nameniu;
@end
Student+Niu.m
@implementation Student (Niu)
//提示方法未实现
//Property 'name' requires method 'name' to be defined - use @dynamic or provide a method implementation in this category
//Property 'name' requires method 'setName:' to be defined - use @dynamic or provide a method implementation in this category
@end
roperty----=>(
    nameniu
)
method----=>(
)
 ivar----=>(
)
 protocol----=>(
)

6.分类属性声明+基类属性声明+实现

Student.h
@interface Student : NSObject
@property (nonatomic, strong)NSString *nameniu;
@end
Student.m
@implementation Student

@end
Student+Niu.h
@interface Student (Niu)
@property(nonatomic,strong) NSString*nameniu;
@end
Student+Niu.m
@implementation Student (Niu)
//不会提示方法未实现,因为基础类已经实现
//Property 'name' requires method 'name' to be defined - use @dynamic or provide a method implementation in this category
//Property 'name' requires method 'setName:' to be defined - use @dynamic or provide a method implementation in this category
@end

property----=>(
    nameniu,
    nameniu
)
 method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
 ivar----=>(
    "_nameniu"
)
protocol----=>(
)

如果在分类实现setNameniu,基础类方法被覆盖
@implementation Student (Niu)
-(void)setNameniu:(NSString *)nameniu{
    
}
property----=>(
    nameniu,(分类属性)
    nameniu(基类属性)
) method----=>(
    "setNameniu:”,(分类方法)
    "setNameniu:”,(基类方法)
    nameniu,
    ".cxx_destruct"
)
 ivar----=>(
    "_nameniu"
)
protocol----=>(
)
@end

main.m
Student *stu =[[Student alloc] init];
 stu.nameniu;
main.cpp
Student *stu =((Student *(*)(id, SEL))(void *)objc_msgSend)((id)((Student *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Student"), sel_registerName("alloc")), sel_registerName("init"));
((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)stu, sel_registerName("nameniu”));//本质调用objc_msgSend,先找分类方法再找基础类方法

7.扩展属性+基类属性+报错 

Student.h
@interface Student : NSObject
@property(nonatomic,strong)NSString*nameniu; //扩展类属性同名必须readonly,@property(nonatomic,strong,readonly)NSString*nameniu;
@end

Student.m
@interface Student()
@property(nonatomic,strong)NSString*nameniu;//Illegal redeclaration of property in class extension 'Student' (attribute must be 'readwrite', while its primary must be 'readonly’)报错
@end
@implementation Student
@end

8.扩展属性+基类属性

Student.h
@interface Student : NSObject
@property(nonatomic,strong,readonly)NSString*nameniu; 
@end
Student.m
@interface Student()
@property(nonatomic,strong)NSString*nameniu;
@end
@implementation Student
@end
property----=>(
    nameniu
)
 method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
ivar----=>(
    "_nameniu"
)
protocol----=>(
)

9.协议属性+分类属性

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end

@interface Student : NSObject<Student>
@end
Student.m
@implementation Student
@end

Student+Niu.h
@interface Student (Niu)
@property(nonatomic,strong)NSString*nameniu;
@end
Student+Niu.m
@implementation Student (Niu)
@end
property----=>(
    nameniu,
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
method----=>(
)
 ivar----=>(
)
 protocol----=>(
    Student
)

10协议属性+分类属性+基类属性

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end

@interface Student : NSObject<Student>
@property(nonatomic,strong)NSString*nameniu;
@end
Student.m
@implementation Student
@end

Student+Niu.h
@interface Student (Niu)
@property(nonatomic,strong)NSString*nameniu;
@end
Student+Niu.m
@implementation Student (Niu)
@end
 property----=>(
    nameniu,
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
 method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
2021-10-14 17:12:25.417797+0800 SSTest[27722:2869065] ivar----=>(
    "_nameniu"
)
2021-10-14 17:12:25.417833+0800 SSTest[27722:2869065] protocol----=>(
    Student
)

11.协议属性+分类属性+基类属性 

Student.h
@protocol Student <NSObject>
@property(nonatomic,strong)NSString*nameniu;
@end

@interface Student : NSObject<Student>
@end
Student.m
@implementation Student
@synthesize nameniu = _nameniu;
@end

Student+Niu.h
@interface Student (Niu)
@property(nonatomic,strong)NSString*nameniu;
@end
Student+Niu.m
@implementation Student (Niu)
@end
2021-10-14 17:14:43.010522+0800 SSTest[27744:2870654] property----=>(
    nameniu,
    nameniu,
    hash,
    superclass,
    description,
    debugDescription
)
2021-10-14 17:14:43.010607+0800 SSTest[27744:2870654] method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
2021-10-14 17:14:43.010664+0800 SSTest[27744:2870654] ivar----=>(
    "_nameniu"
)
2021-10-14 17:14:43.010700+0800 SSTest[27744:2870654] protocol----=>(
    Student
)

12.添加属性

12. 添加属性
Student *stu =[[Student alloc] init];
stu.nameniu;
unsigned int count=5;
objc_property_attribute_t attribute[count];
//添加类型
objc_property_attribute_t t1;
t1.name="T";
t1.value="NSString";
//添加ivar
objc_property_attribute_t t2;
t2.name="V";
t2.value="_mood";
//添加  nonatomic
objc_property_attribute_t t3;
t3.name="N";
t3.value="";
//添加  copy
objc_property_attribute_t t4;
t4.name="C";
t4.value="";
//添加 readonly
objc_property_attribute_t t5;
t5.name="R";
t5.value="";
attribute[0]=t1;
attribute[1]=t2;
attribute[2]=t3;
attribute[3]=t4;
attribute[4]=t5;
bool isSuccess=class_addProperty(objc_getClass("Student"), "sex", attribute, count);

property----=>(
    sex,
    nameniu,
    nameniu
)
2021-10-15 15:55:26.447339+0800 SSTest[40355:3601084] method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
2021-10-15 15:55:26.447429+0800 SSTest[40355:3601084] ivar----=>(
    "_nameniu"
)	

13.修改属性 

修改属性
Student *stu =[[Student alloc] init];
stu.nameniu;

unsigned int count=4;
objc_property_attribute_t  attribute[count];

objc_property_attribute_t t1;
t1.name="T";
t1.value="NSString";

objc_property_attribute_t t2;
t2.name="V";
t2.value="_cName";

objc_property_attribute_t t3;
t3.name="N";
t3.value="";

objc_property_attribute_t t4;
t4.name="C";
t4.value="";

attribute[0]=t1;
attribute[1]=t2;
attribute[2]=t3;
attribute[3]=t4;

class_replaceProperty(objc_getClass("Student"), "nameniu", (const objc_property_attribute_t*)&attribute, count);

property_getAttributes----=>TNSString,V_cName,N,C
2021-10-15 16:08:12.860201+0800 SSTest[40609:3611828] property----=>(
    nameniu
)
2021-10-15 16:08:12.860290+0800 SSTest[40609:3611828] method----=>(
    nameniu,
    "setNameniu:",
    ".cxx_destruct"
)
2021-10-15 16:08:12.860338+0800 SSTest[40609:3611828] ivar----=>(
    "_nameniu"
)

分析
struct property_t {
    const char *name;
    const char *attributes;
};
class_replaceProperty调用_class_addProperty
_class_addProperty
if (prop) {
        // replace existing
        rwlock_writer_t lock(runtimeLock);
        try_free(prop->attributes);
        prop->attributes = copyPropertyAttributeString(attrs, count);
        return YES;
}
注:只改变了 prop->attributes,没有改变prop->name

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值