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