iOS RunTime之五:Category 面试题

面试题:为什么 Category 中不能动态添加成员变量?

解答:

很多人在面试的时候都会被问到 Category,既然允许用 Category 给类增加方法和属性,那为什么不允许增加成员变量?

Objective-C 提供的 runtime 函数中,确实有一个 class_addIvar() 函数用于给类添加成员变量,但是阅读过苹果的官方文档的人应该会看到:

This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.

大概的意思说,这个函数只能在“构建一个类的过程中”调用。当编译类的时候,编译器生成了一个实例变量内存布局 ivar layout,来告诉运行时去那里访问类的实例变量们,一旦完成类定义,就不能再添加成员变量了。经过编译的类在程序启动后就被 runtime 加载,没有机会调用 addIvar。程序在运行时动态构建的类需要在调用 objc_registerClassPair 之后才可以被使用,同样没有机会再添加成员变量。

Paste_Image.png

从运行结果中看出,你不能为一个类动态的添加成员变量,可以给类动态增加方法和属性。

因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了 isa 指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在 objc_class 中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。

同理:

Paste_Image.png

某一个类的分类是在 runTime 时,被动态的添加到类的结构中。 想了解分类是如何加载的请看 iOS RunTime之六:Category

CategoryExtension 的区别

  • Extension 在编译期决议,它就是类的一部分,在编译期和头文件里的 @interface 以及实现文件里的 @implement 一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。Extension 一般用来隐藏类的私有信息,你必须有一个类才能为这个类添加 Extension,所以你无法为系统的类比如 NSString 添加 Extension
  • Category 则完全不一样,它是在运行期决议的。
  • Extension 可以添加成员变量,而 Category 一般不可以。

总之,就 CategoryExtension 的区别来看,Extension 可以添加成员变量,而 Category 是无法添加成员变量的。因为 Category 在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局。

面试题

一般面试官有时候会问到这样的问题: 在类和Category中都可以有study方法,那么有两个问题:

  • 在类的study方法调用的时候,我们可以调用Category中声明的study方法么?
  • 如果一个类有多个分类的时候study方法,调用顺序是咋样的呢?

解决方法: iOS之+load和+initialize的区别

如果有觉得上述我讲的不对的地方欢迎指出,大家多多交流沟通。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏jouypub

MySQL中utf8和utf8mb4的区别

MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是ut...

19080
来自专栏PHP在线

PHP那些“坑”

字符串 == 比较类型强转隐患 http://php.net/manual/zh/language.operators.comparison.php // ph...

32930
来自专栏calmound

散列表

http://blog.csdn.net/yyxaf/article/details/7527878 搜索关键词:散列函数、散列表、哈希函数、哈希表、Hash函...

383120
来自专栏java工会

导致程序崩溃的一行代码,你有写过吗?

初学编程时,可能经常遇到一些程序崩溃的现象。一般来说,程序崩溃由于操作不当引起的。但是有时候,因为一个程序员的粗心,正式版本的程序出现崩溃状况这就很不因该了。之...

12820
来自专栏大史住在大前端

野生前端的数据结构基础练习(2)——队列

循环队列书中并没有提及,它是一种特殊的队列。简单理解就是将基本队列只当做存储结构,而使用front和rear两个指针分别代表队列的头和尾,实际对外表现的队列是f...

22330
来自专栏Java爬坑系列

【JAVA零基础入门系列】Day5 Java中的运算符

  运算符,顾名思义就是用于运算的符号,比如最简单的+-*/,这些运算符可以用来进行数学运算,举个最简单的栗子:   已知长方形的长为3cm,高为4cm,求长方...

21170
来自专栏Brian

Python进阶教程(一)

概述 hi,朋友们大家好,今天将英文原著作者 @yasoob《Intermediate Python》进行翻译和在工作中使用的Python技巧进行了总结。Git...

38770
来自专栏java一日一条

Java高级特性之枚举学习总结

在Java SE5之前,我们要使用枚举类型时,通常会使用static final 定义一组int常量来标识,代码如下

12220
来自专栏互联网杂技

StackOverflow上关于JavsScript的热门问答

Q1:javascript的闭包是如何工作的? 正如爱因斯坦所说的: 如果你不能把它解释给一个六岁的小孩,说明你对它还不够了解。 我曾尝试向一个27岁的朋友解释...

33760
来自专栏铭毅天下

干货 | Elasticsearch5.X Mapping万能模板

0、引言 在关系型数据库如Mysql中,设计库表需要注意的是: 1)需要几个表; 2)每个表有哪些字段; 3)表的主键及外键的设定——便于有效关联。 表的设计遵...

499130

扫码关注云+社区

领取腾讯云代金券