vicki753's iOS 基础--类结构
我们现在说说类结构吧,不仅仅是类方法存在哪儿,又或者说实例是在堆里,变量在栈里,现在挑战的是内部剖析。
本来我想这样做的:
zhengyis-MacBook-Pro:TabBarViewController zhengyi$ clang -rewrite-objc ViewController.m
In file included from ViewController.m:9:
./ViewController.h:9:9: fatal error: 'UIKit/UIKit.h' file not found
#import <UIKit/UIKit.h>
^~~~~~~~~~~~~~~
1 error generated.
但是clang它找不到UIKit框架。
foundation是基础框架,所以clang是可以控制的,foundation 是在 core service 层的,UIKit 是在cocotouch层的。所以,我果断换foundation框架里面的类了,NSNumber 继承它,创建了.h和.m文件:
.h
#import <Foundation/Foundation.h>
@interface ZYNumberTest : NSNumber
@property (nonatomic, assign) int abc;
- (void)checkTheThings;
- (void)checkTheThingsWithParameters:(NSString *)parameters;
@end
.m
#import "ZYNumberTest.h"
@implementation ZYNumberTest
- (void)checkTheThings {
int a = 1;
int b = 2;
int c = a + b;
}
- (void)checkTheThingsWithParameters:(NSString *)parameters {
NSLog(@"----parameters-- -%@", parameters);
}
@end
总共这几行代码,使用命令:clang -rewrite-objc ZYNumberTest.m
得到ZYNumberTest.cpp文件,97990行。还是够多的了。
这里面可以看出系统为我们这几行代码做了很多处理。大写的6,这种感觉就好像打开石榴里面全是红色透明的果肉,精细而且思维紧密。
1、这里面大量使用了struct结构体,方便和间接开阔空间
2、使用了大量的内联函数 inline
3、使用了大量 extern 有定义系统编号macosx
4、 #pragma clang assume_nonnull begin和#pragma clang assume_nonnull end 这个就和我们平时接触的#define NS_ASSUME_NONNULL_BEGIN 和 #define NS_ASSUME_NONNULL_END 一样吧
5、大量的 OSStatus定义
6、extern "C"{} 这个的意思是在。cpp文件中定义c语言
再分析下详细的代码吧~~虽然有很多专业名词很陌生,但是可以感受初代码拆分很(hao)精(tou)细(teng):
static struct _class_ro_t _OBJC_CLASS_RO_$_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
0, __OFFSETOFIVAR__(struct ZYNumberTest, _abc), sizeof(struct ZYNumberTest_IMPL),
(unsigned int)0,
0,
"ZYNumberTest",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_ZYNumberTest,
0,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_ZYNumberTest,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_ZYNumberTest,
};
-
👆这里面说了总结了几个列表声明:method list ,ivar list, prop list.
struct _class_ro_t { unsigned int flags; unsigned int instanceStart; unsigned int instanceSize; unsigned int reserved; const unsigned char *ivarLayout; const char *name; const struct _method_list_t *baseMethods; const struct _objc_protocol_list *baseProtocols; const struct _ivar_list_t *ivars; const unsigned char *weakIvarLayout; const struct _prop_list_t *properties; }; static struct _class_ro_t _OBJC_METACLASS_RO_$_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = { 1, sizeof(struct _class_t), sizeof(struct _class_t), // 结构体class_t的大小 (unsigned int)0, 0, "ZYNumberTest", 0, 0, 0, 0, 0, };
-
👆 这里可以看出 _class_ro_t 包含了许多属性
struct _class_t { struct _class_t *isa; struct _class_t *superclass; void *cache; void *vtable; struct _class_ro_t *ro; };
-
👆 在这里终于看到isa 指针了,类指针。同时可以看到superclass 指针。
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSNumber;
extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;
extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_NSObject, 这里的注释应该就是 0 的意思
0, // &OBJC_METACLASS_$_NSNumber,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_METACLASS_RO_$_ZYNumberTest, // 这里是给出class_ro_t的地址
};
- 👆可以看到class_t 结构体的实现
extern "C" unsigned long OBJC_IVAR_$_ZYNumberTest$_abc;
struct ZYNumberTest_IMPL {
struct NSNumber_IMPL NSNumber_IVARS;
int _abc;
};
- 👆 可以看到abc 这个属性,在这里 ZYNumberTest_IMPL 用这个来结构体定义,NSNumber_IMPL NSNumber_IVARS 可以看出是NSNumber类型的标示,以及下划线_abc 的标示。
static int _I_ZYNumberTest_abc(ZYNumberTest * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_ZYNumberTest$_abc)); }
static void _I_ZYNumberTest_setAbc_(ZYNumberTest * self, SEL _cmd, int abc) { (*(int *)((char *)self + OBJC_IVAR_$_ZYNumberTest$_abc)) = abc; }
-
👆这里可以发现实现了get方法和set方法
extern "C" unsigned long int OBJC_IVAR_$_ZYNumberTest$_abc __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct ZYNumberTest, _abc); static struct /*_ivar_list_t*/ { unsigned int entsize; // sizeof(struct _prop_t) unsigned int count; struct _ivar_t ivar_list[1]; } _OBJC_$_INSTANCE_VARIABLES_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_ivar_t), 1, {{(unsigned long int *)&OBJC_IVAR_$_ZYNumberTest$_abc, "_abc", "i", 2, 4}} };
-
👆 这里介绍的主要是变量abc的大小
struct _prop_t {
const char *name;
const char *attributes;
};
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_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_prop_t),
1,
{{"abc","Ti,N,V_abc"}}
};
-
👆 这里介绍的是属性
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[4]; } _OBJC_$_INSTANCE_METHODS_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 4, {{(struct objc_selector *)"checkTheThings", "v16@0:8", (void *)_I_ZYNumberTest_checkTheThings}, {(struct objc_selector *)"checkTheThingsWithParameters:", "v24@0:8@16", (void *)_I_ZYNumberTest_checkTheThingsWithParameters_}, {(struct objc_selector *)"abc", "i16@0:8", (void *)_I_ZYNumberTest_abc}, {(struct objc_selector *)"setAbc:", "v20@0:8i16", (void *)_I_ZYNumberTest_setAbc_}} };
-
👆 同样在这里可以看到method是有四个的,两个实例方法 ,get方法和setter方法
static NSInteger staticIntegerA = 10; static NSString *staticSrtringA = (NSString *)&__NSConstantStringImpl__var_folders_kb_8c_mh41d58bg056b0ts_fjdr0000gn_T_ZYNumberTest_712319_mi_0;
-
👆 静态变量就只需要这样的声明就行整个文件都可以引用,并不在某个结构体中,不像abc这个变量,它是包含在类的实例中的,从get和set方法中可以看出
那类方法去哪儿了呢?
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_$_CLASS_METHODS_ZYNumberTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"userClassMethod", "v16@0:8", (void *)_C_ZYNumberTest_userClassMethod}}
};
-
👆 如果添加了类方法,它就会出现这个结构体,可以看到实例方法(_INSTANCE_METHODS_ZYNumberTest)和类方法(_CLASS_METHODS_ZYNumberTest)完全是分开的。
static void _I_ZYNumberTest_checkTheThings(ZYNumberTest * self, SEL _cmd) { int a = 1; int b = 2; int c = a + b; }
-
👆这个是实例方法,就只需要这样声明就行。
static void _I_ZYNumberTest_checkTheThingsWithParameters_(ZYNumberTest * self, SEL _cmd, NSString *parameters) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_kb_8c_mh41d58bg056b0ts_fjdr0000gn_T_ZYNumberTest_712319_mi_1, parameters); }
-
👆这个就是带参数的实例方法
static void _C_ZYNumberTest_userClassMethod(Class self, SEL _cmd) { }
-
👆类方法的实现
=============== 2018/08/01 =============== -
接下来如果是类别呢?
首先,不管这个是不是类别,都会有类别定义的,所以可想而知,它们的初始化创建在这里就已经确定好了。👇
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
如果文件是类别文件 👇
.h
#import "ZYNumberTest.h"
@interface ZYNumberTest (ZY)
-(void)userCatergory;
-(void)userCatergoryWithParameters:(NSString *)parameters;
+(void)userClassMethodForCatergory;
@end
.m
#import "ZYNumberTest+ZY.h"
@implementation ZYNumberTest (ZY)
-(void)userCatergory {}
-(void)userCatergoryWithParameters:(NSString *)parameters {}
+(void)userClassMethodForCatergory { }
@end
就会是这样的实现(这是没有添加方法的)👇
static struct _category_t _OBJC_$_CATEGORY_ZYNumberTest_$_ZY __attribute__ ((used, section ("__DATA,__objc_const"))) =
{
"ZYNumberTest",
0, // &OBJC_CLASS_$_ZYNumberTest,
0,
0,
0,
0,
};
static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {
&_OBJC_$_CATEGORY_ZYNumberTest_$_ZY,
};
-
这是添加方法了的👇
static struct _category_t _OBJC_$_CATEGORY_ZYNumberTest_$_ZY __attribute__ ((used, section ("__DATA,__objc_const"))) = { "ZYNumberTest", 0, // &OBJC_CLASS_$_ZYNumberTest, (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_ZYNumberTest_$_ZY, 0, 0, 0, }; static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= { &_OBJC_$_CATEGORY_ZYNumberTest_$_ZY, }; static void _I_ZYNumberTest_ZY_userCatergory(ZYNumberTest * self, SEL _cmd) {} // 实例方法 static void _I_ZYNumberTest_ZY_userCatergoryWithParameters_(ZYNumberTest * self, SEL _cmd, NSString *parameters) {} // 实例方法 static void _C_ZYNumberTest_ZY_userClassMethodForCatergory(Class self, SEL _cmd) {} // 类方法 static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[2]; } _OBJC_$_CATEGORY_INSTANCE_METHODS_ZYNumberTest_$_ZY __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 2, {{(struct objc_selector *)"userCatergory", "v16@0:8", (void *)_I_ZYNumberTest_ZY_userCatergory}, {(struct objc_selector *)"userCatergoryWithParameters:", "v24@0:8@16", (void *)_I_ZYNumberTest_ZY_userCatergoryWithParameters_}} };
-
这是实现的方法,CATEGORY_INSTANCE_METHODS_ZYNumberTest这个的意思就是指这个是实例的方法👇
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[1]; } _OBJC_$_CATEGORY_CLASS_METHODS_ZYNumberTest_$_ZY __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 1, {{(struct objc_selector *)"userClassMethodForCatergory", "v16@0:8", (void *)_C_ZYNumberTest_ZY_userClassMethodForCatergory}} };
然后如果是子类,父类的特性也会保留所以里面就多了下面这段话代码 ,这里的ZYNumberTest是父类,ZYNumberTestSubClass是子类👇
#ifndef _REWRITER_typedef_ZYNumberTest
#define _REWRITER_typedef_ZYNumberTest
typedef struct objc_object ZYNumberTest;
typedef struct {} _objc_exc_ZYNumberTest;
#endif
struct ZYNumberTest_IMPL {
struct NSNumber_IMPL NSNumber_IVARS;
};
还有一段关于一下superclass的实现👇
static void OBJC_CLASS_SETUP_$_ZYNumberTestSubClass(void ) {
OBJC_METACLASS_$_ZYNumberTestSubClass.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_ZYNumberTestSubClass.superclass = &OBJC_METACLASS_$_ZYNumberTest;
OBJC_METACLASS_$_ZYNumberTestSubClass.cache = &_objc_empty_cache;
OBJC_CLASS_$_ZYNumberTestSubClass.isa = &OBJC_METACLASS_$_ZYNumberTestSubClass;
OBJC_CLASS_$_ZYNumberTestSubClass.superclass = &OBJC_CLASS_$_ZYNumberTest;
OBJC_CLASS_$_ZYNumberTestSubClass.cache = &_objc_empty_cache;
}
-
父类的类型就是这里可以看出了,如果是NSObject的话就是 👇
OBJC_METACLASS_$_ZYObjectTest.superclass = &OBJC_METACLASS_$_NSObject;
-
如果是NSNumber的话就是: 👇
OBJC_METACLASS_$_ZYNumberTest.superclass = &OBJC_METACLASS_$_NSNumber;
以上就是对类的属性、类结构、实例方法、类方法、类别方法的简单介绍,大概的类结构就是这样,再深入理解一下isa这个指针。👉
isa
-
我们为什么要说这个isa呢?看了这么多的解析出的.cpp代码和参考文章之后,觉得,isa就像一个可以贯穿整篇文章线索,所有的一切都是围绕着这个线索,离不开它,我们看看它在哪些地方出现的:
-
在类/对象 这里面出现
typedef struct objc_class *Class; struct objc_object { Class _Nonnull isa __attribute__((deprecated)); }; typedef struct objc_object *id; typedef struct objc_selector *SEL;
-
协议结构体中出现
struct _protocol_t { void * isa; // NULL const char *protocol_name; const struct _protocol_list_t * protocol_list; // super protocols const struct method_list_t *instance_methods; const struct method_list_t *class_methods; const struct method_list_t *optionalInstanceMethods; const struct method_list_t *optionalClassMethods; const struct _prop_list_t * properties; const unsigned int size; // sizeof(struct _protocol_t) const unsigned int flags; // = 0 const char ** extendedMethodTypes;
};
-
在方法IMP结构体里面
struct NSObject_IMPL { Class isa; };
-
在代理结构体里面
struct NSProxy_IMPL { Class isa; };
objc_object 这个结构体,在代码里面多处出现,
#ifndef _REWRITER_typedef_NSMutableArray
#define _REWRITER_typedef_NSMutableArray
typedef struct objc_object NSMutableArray;
typedef struct {} _objc_exc_NSMutableArray;
#endif
因为都是在定义为“类”,大部分都是NS开头的类,这个文件搜索出
“objc_object+空格” 后结果出来了841, “objc_object+空格+NS” 搜索出来的是822,
但是不明白为什么会有多个这样的定义? 这里还不知道❌
但可以肯定的是它们每一个都是一个对象,也就是每一个对象都有一个isa指针。
参考文章:介绍isa:
http://www.cocoachina.com/ios/20160503/16060.html
https://blog.csdn.net/kuangdacaikuang/article/details/53415655