vicki753's iOS 基础--类结构

2018-08-01  本文已影响19人  vicki753

我们现在说说类结构吧,不仅仅是类方法存在哪儿,又或者说实例是在堆里,变量在栈里,现在挑战的是内部剖析。

本来我想这样做的:

  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,
};
  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的地址
};
        extern "C" unsigned long OBJC_IVAR_$_ZYNumberTest$_abc;
        struct ZYNumberTest_IMPL {
    struct NSNumber_IMPL NSNumber_IVARS;
  int _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; }
  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[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}}
};

首先,不管这个是不是类别,都会有类别定义的,所以可想而知,它们的初始化创建在这里就已经确定好了。👇

  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,
};

然后如果是子类,父类的特性也会保留所以里面就多了下面这段话代码 ,这里的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;
 }

以上就是对类的属性、类结构、实例方法、类方法、类别方法的简单介绍,大概的类结构就是这样,再深入理解一下isa这个指针。👉

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

上一篇 下一篇

猜你喜欢

热点阅读