一、如果让你实现属性的weak,如何实现的?

PS: @property 等同于在.h文件中声明实例变量的get/set方法, 而其中property有一些关键字,其中就包括weak,atomic的。

对 weak 属性的理解:

理解一:为这种属性设置值时,设置方法既不保留新设置的值,也不释放之前设置的值, 不过在属性所指的对象遭到摧毁时,属性值就会清空。

理解二:在setter方法中,需要对传入的对象不进行引用计数加1的操作。简单来说,就是对传入的对象没有所有权,当该对象引用计数为0时,即该对象被释放后,用weak声明的实例变量指向nil。

如何实现 属性的weak, 最关键的就是设置如何当 Object Dealloc 的时候设置 为nil

只是应对某个具体属性的场景:

1、写 Setter 方法时,将其新值 关联一个 对象 (objc_setAssociatedObject)

2、并且实现该关联对象的一个回调方法 ,在回调方法中 将新值 设置为 nil。

当然该回调方法的执行地方是在 dealloc 中实现的。

详细可以看:【Objcective-C 高级编程 iOS 与 OS X多线程和内存管理】中第一章第四节 __weak 修饰符(我直接在书中看的,链接无效)

或者直接看:招聘一个靠谱iOS 程序员中第八节 runtime 如何实现 weak 属性

二、如果让你来实现属性的atomic,如何实现?

2-1、对 atomic 的理解

atomic意为操作是原子的,意味着只有一个线程访问实例变量。atomic是线程安全的,至少在当前的存取器上是安全的。

2-2、如何实现 属性的atomic,其实就是对线程安全的考察。

最简单的方法就是, 直接加线程锁

用runtime方法

直接加线程锁, 实现粗略的atomic

- (void)setTestObj:(id)testObj {@synchronized(self) {if(testObj != _testObj) {            _testObj = testObj;        }    }}- (id)testObj {@synchronized(self) {return_testObj;    }}

用runtime实现, 注意该系列方法需要自己引入:

externvoidobjc_setProperty(idself, SEL _cmd, ptrdiff_t offset,idnewValue,BOOLatomic,BOOLshouldCopy);externidobjc_getProperty(idself, SEL _cmd, ptrdiff_t offset,BOOLatomic);externvoidobjc_copyStruct(void*dest,constvoid*src, ptrdiff_t size,BOOLatomic,BOOLhasStrong);

上面那几个函数已经被实现了,但没有被声名。如果要使用他们,必须自己声名。具体来源:https://opensource.apple.com/source/objc4/objc4-371.2/runtime/Accessors.subproj/objc-accessors.h

#define AtomicRetainedSetToFrom(dest, source) objc_setProperty(self, _cmd, (ptrdiff_t)(&dest) - (ptrdiff_t)(self), source, YES, NO)#define AtomicCopiedSetToFrom(dest, source) objc_setProperty(self, _cmd, (ptrdiff_t)(&dest) - (ptrdiff_t)(self), source, YES, YES)#define AtomicAutoreleasedGet(source) objc_getProperty(self, _cmd, (ptrdiff_t)(&source) - (ptrdiff_t)(self), YES)#define AtomicStructToFrom(dest, source) objc_copyStruct(&dest,&source, sizeof(__typeof__(source)), YES, NO)

- (void)setTestStr:(NSString *)testStr {    AtomicCopiedSetToFrom(_testStr,testStr);}- (NSString *)testStr {returnAtomicAutoreleasedGet(_testStr);}

用runTime这个方法是从网上摘录下来的,据说速度和安全性肯定是更好的 ,对于此处暂时做了解。

2-3、实际参考的是:

objc系列译文(2.4):线程安全类的设计

http://www.cocoawithlove.com/2009/10/memory-and-thread-safe-custom-property.html

三、KVO为什么要创建一个子类来实现?

这个题考察的实际上 KVO 的实现机制,或者说 KVO 的实现机制为什么是这样的?

3-1、 KVO 大致实现机制:

简单的说,在我们对某个对象完成监听的注册后,编译器会修改监听对象的isa指针,让这个指针指向一个新生成的中间类 (子类),然后子类重写所有的setter方法,并且该子类的- (Class) class和- (Class) superclass方法会被重写,返回父类(原始类)的Class,最后将当前对象的类改为这个KVO前缀的子类。

NSObject(NSKeyValueObserving)NSObject(NSKeyValueObserverRegistration)NSObject(NSKeyValueObservingCustomization)

 
 

KVO 实现图 -- 源自iOS程序犭袁

3-2、为什么要创建一个子类来实现?

可以这样说,如果我们不通过创建子类,那可以通过什么方法来实现呢?

提前知道的:通过子类继承父类属性并重写了它的setter方法,当这个属性被改变时,KVO 就可以观察到。

通过method_swizzling方法来进行观察值?

如最常用观察的UITableView的contentOffset, 此处如果直接在 Setter 方法中用 method_swizzling 的方法,那么所有的UITableView都会受到影响,而我们一个 App 中不止一个UITableView。

一个衍生的 KVO 注销的坑

另外也可以从另一个角度理解,为什么使用 KVO 之后最后要记得移除它,创建了自然要销毁嘛,但是同时也得注意一个移除的坑:

[_tableViewremoveObserver:selfforKeyPath:@"contentOffset"context:nil];

context这块我们通常写 nil, 但偶尔这样是有问题的,当对同一个keypath进行两次removeObserver时会导致程序 Crash ,这种情况常常出现在父类有一个 KVO ,父类在dealloc中remove了一次,子类又remove了一次的情况下。 所以这块我建议context在由继承的情况下尽量 写一个标识值。

详细可以看看这篇KVO进阶 —— 源码实现探究

四、类结构体的组成,isa指针指向了什么?(这里应该将元类和根元类也说一下)

4-1、此处考察的应该是 Objective-C 的对象本质。

Objective-C中的对象本质上是结构体对象,其中isa是它唯一的私有成员变量。

此处是在objc.h文件中看到的:

#if !OBJC_TYPES_DEFINED/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;/// Represents aninstanceof a class.struct objc_object {    Class isa  OBJC_ISA_AVAILABILITY;};/// A pointer to aninstanceof a class.typedef struct objc_object *id;#endif

类结构体的组成

此处是 是在runtime.h文件中就可以看到的:

structobjc_class {    Class isa  OBJC_ISA_AVAILABILITY;// isa 指针#if!__OBJC2__Class super_class                                        OBJC2_UNAVAILABLE;// 父类constchar*name                                        OBJC2_UNAVAILABLE;// 类名longversion                                            OBJC2_UNAVAILABLE;// 类的版本号longinfo                                                OBJC2_UNAVAILABLE;// 类的信息longinstance_size                                      OBJC2_UNAVAILABLE;// 实例大小structobjc_ivar_list *ivars                            OBJC2_UNAVAILABLE;// 成员变量列表structobjc_method_list **methodLists                    OBJC2_UNAVAILABLE;// 方法列表structobjc_cache *cache                                OBJC2_UNAVAILABLE;// 方法缓存structobjc_protocol_list *protocols                    OBJC2_UNAVAILABLE;// 协议列表#endif} OBJC2_UNAVAILABLE;/* Use `Class` instead of `struct objc_class *` */

从上面我们就可以看出其基本组成部分啦,其中成员变量列表,方法列表,方法缓存,及协议列表又是结构体,另外特别要注意下isa指针。

4-2、 isa指针是指向 metaClass (元类)

metaClass是什么?

这就引出了metaClass的定义:metaClass是Class对象的类。

当你向一个对象发送消息,就在那个对象的方法列表中查找那个消息。

当你想一个类发送消息,就再那个类的metaClass中查找那个消息。

每个类都必须有一个唯一的metaClass,因为每个Class都有一个可能不一样的类方法。

每个类里面都有个isa指针,这个isa指针是指向metaClass(元类)。

 
 

图中步骤解释:

1、当[NSObject alloc]的时候,runtime库会通过Class的isa指针找到该类的metaClass(元类)。并在该类的metaClass(元类)的methodLists方法列表中去查找alloc方法。

2、如果该类的metaClass(元类)的方法列表中没找到alloc方法,那么就会向metaClass(元类)的基类的metaClass(元类)发送消息。而基类的metaClass则是指向自己的。

参考:

Objective-C 中的 MetaClass 是什么?

Objective-C Runtime(一)对象模型及类与元类

五、 RunLoop有几种事件源?有几种模式?

5-1、RunLoop有几种事件源?

Run Loop对象处理的事件源分为两种:Input sources 和 Timer sources。

Input sources:用分发异步事件,通常是用于其他线程或程序的消息。

Timer sources:用分发同步事件,通常这些事件发生在特定时间或者重复的时间间隔上(Timer事件(Schedule或者Repeat))。

 
 

经典 RunLoop 图

5-2、RunLoop有有几种模式?

NSDefaultRunLoopMode :默认状态下,不滑动,空闲状态,程序启动之后就会被切到这个mode

UITrackingRunLoopMode : 滑动的时候

UIInitializationRunLoopMode:私有的,可以追踪到的,这个app启动的时候是这个mode,第一个页面加载之后才回到第一个mode

NSRunLoopCommonModes:默认情况包括下第一个第二个,在这种情况下就是这两种情况都可以执行

这个要展开的太多了,还是多看两遍YY 大神的 深入理解RunLoop

六、方法列表的数据结构是什么?

感觉是由于目前热更新火的的原因,此处考察一下动态加载的原理

PS: 今天最大的消息,苹果对使用 JSPatch 的App 进行警告了。。。

不过了解下objc_method和objc_method_list还是有必要的

类中每一个方法在内部转换后的结构体objc_method

每一个类拥有的的函数列表objc_method_list

structobjc_method{    SEL method_name                                          OBJC2_UNAVAILABLE;// 函数名称char*method_types                                      OBJC2_UNAVAILABLE;// 函数类型IMP method_imp                                          OBJC2_UNAVAILABLE;//函数的具体实现()}                                                            OBJC2_UNAVAILABLE;

方法列表的数据结构也就如下了:

structobjc_method_list {structobjc_method_list *obsolete                        OBJC2_UNAVAILABLE;// 函数列表intmethod_count                                        OBJC2_UNAVAILABLE;// 函数中的个数#ifdef__LP64__intspace                                                OBJC2_UNAVAILABLE;#endif/* variable length structure */structobjc_method method_list[1]                        OBJC2_UNAVAILABLE;// 函数列表中的第一个函数地址}

通常使用了上述方法,下面这个方法一定是要了解的。

OBJC_EXPORTBOOLclass_addMethod(Classcls,SELname,IMPimp,constchar*types)OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

/**

* Class 给哪个类添加方法

* sel 要添加的方法编号(方法名)

* IMP 方法的实现 ———— 函数的入口(函数的指针 函数名 是啥都可以 不一定和sel相同)

* types 方法的类型 编码格式 (类型c语言的字符串) (函数的类型:返回值类型 参数类型 直接查文档 文档有表格)

”v@:”意思就是这已是一个void类型的方法,没有参数传入。

“i@:”就是说这是一个int类型的方法,没有参数传入。

”v@:@”意思就是这已是一个void类型的方法,有参数传入。

*/class_addMethod([self class], sel,@selector(testMethod),"v@:");

此处需要多了解下 runtime 中关于方法的一系列。

七、 分类是如何实现的?它为什么会覆盖掉原来的方法?

先真正的看一下Category

typedefstructcategory_t{constchar*name;// 类的名字classref_tcls;// 类structmethod_list_t*instanceMethods;// 所有给类添加的实例方法的列表structmethod_list_t*classMethods;// 所有添加的类方法的列表structprotocol_list_t*protocols;// 实现的所有协议的列表structproperty_list_t*instanceProperties;// 添加的所有属性}category_t;

7-1、分类是如何实现的?

简单的通俗说:Category实际上就变成了一个方法列表, 被插入到类的信息内, 这样查表的时候就能找到Category内的方法。

将 Category 和它的主类(或元类)注册到哈希表中;

如果主类(或元类)已实现,那么重建它的方法列表。

此处需要知道是,它分为两种情况:Category中的实例方法、协议以及属性添加到类上;而Category的类方法和协议添加到类的metaclass上的。

7-2、分类为什么会覆盖掉原来的方法?

PS: 实际上如果Category和原来类都有相同的方法(testMethod),那么Category附加完成之后,类的方法列表里会有两个该方法(testMethod),而不是直接替换的。

Category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的Category的方法会“覆盖”掉原来类的同名方法,这是因为运行时在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会停止了。

7-3、 此题的答案来源:

对于具体的实现,确实需要看源代码,我是通过下面两篇解读了解的:

Objective-C Category 的实现原理、深入理解Objective-C:Category。

原文链接:https://www.jianshu.com/p/d569c57773ae

ios面试题来一波的更多相关文章

  1. 最全的iOS面试题及答案-转载

    1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么? 答: Object-c的类不可以多重继承:可以实现多个接口,通过实现 ...

  2. IOS面试题总结

    iOS面试题: 一:网络理论知识的理解 1:Internet物理地址和IP地址转换采用什么协议 ARP(Address Resolution Protocol)地址解析协议 2:Internet采用哪 ...

  3. iOS面试题及答案2015.6.7

    iOS面试题及答案     1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么? 答: Object-c的类不可以多重继承 ...

  4. iOS 面试题 总结

    #include <iostream> using namespace std; int main () { char p[]={'a','b','c'}, q[]="abc&q ...

  5. [转载]iOS面试题总

    转载自:http://blog.sina.com.cn/s/blog_67eb608b0101r6xb.html (2014-06-13 20:23:33) 转载▼ 标签: 转载   crash 原文 ...

  6. 试答卓同学的 iOS 面试题

    卓同学昨天写了一篇文章<4道过滤菜鸟的iOS面试题>.我手痒决定默写一个参考答案.后来发现不认真回答被大家喷成狗,所以决定积极改造,重新做人.下面就是修编之后的答案. 1. struct和 ...

  7. iOS面试题大全-点亮你iOS技能树

    所有的内容大部分来自于网络的搜集,所以我不是一个创造者,而是一个搬运工.我尽量把题目,尤其是参考答案的出处列明.若有任何疑问,建议,意见,请联系我. 第一部分面试题来源于iOS-Developer-I ...

  8. 原 iOS面试题收集

    原 iOS面试题收集 发表于2年前(2013-07-22 13:47)   阅读(369) | 评论(0) 4人收藏此文章, 我要收藏 赞0 听云性能监测产品App.Server.CDN免费试用,绑定 ...

  9. ios 面试题 经典(比较全) 根据重点总结

    史上最全的iOS面试题及答案 1.写一个NSString类的实现 + (id)initWithCString:(c*****t char *)nullTerminatedCString encodin ...

随机推荐

  1. 多模块Maven项目如何使用javadoc插件生成文档

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   需求 最近要对一个项目结构如下的Maven项目生成JavaDoc文档. Project                  ...

  2. activemq 控制面板里的 Number Of Pending Messages、 Messages Enqueued、Messages Dequeued含

    Number Of Consumers  消费者 这个是消费者端的消费者数量 Number Of Pending Messages 等待消费的消息 这个是当前未出队列的数量.可以理解为总接收数-总出队 ...

  3. Bridging and Bonding with CentOS 6.5

    eth0和eth1要做bond,然后kvm虚拟机通过bridge与外界通信. 那么就要在bond上做bridge.配置文件例如以下,实測这样配置,能够从kvm虚拟机ping通外界拓扑. ifcfg-e ...

  4. 【高德地图SDK】如何实现轨迹平滑移动?

    很多人应该都有类似的经历,叫完车,想看看车离我还有多远距离?但手机屏幕上的车不是一动不动,就是一跳一跳的漂移. 目前市面上大多产品“轨迹平滑移动”做的并不好. 市面上只有快的打车和一号专车实现了平滑移 ...

  5. asp.net对象合并

    public class com { /// <summary> /// 把参数转为JSON字符串 /// </summary> /// <param name=&quo ...

  6. 第九周(1) Word邮件合并2

    第九周(1) Word邮件合并2 教学时间 2013-4-22 教学课时 2 教案序号 15 教学目标 1.进一步掌握邮件合并的技巧和方法.2.利用邮件合并制作准考证.3.掌握在同一页生成多个记录的方 ...

  7. Excel 2007 若干技巧。

    1.自定义序列 office按钮→excel选项→常用→编辑自定义列表 2.无法清空剪贴板错误的处理办法: 取消"显示粘贴选项"选项 3.每次选定同一单元格 输入后按ctrl+En ...

  8. How to check WWN and Multipathing on Windows Server

    There are many ways to find the World Wide Name (WWN) of fibre channel HBA connected to windows serv ...

  9. 动态加载jar包(二)

    上次说的加载jar包,有几个问题没有解决: 1.如果项目包含了其他的jar包如何解决? 2.如何规范上传的jar包的类和方法? 下面就解决一下上面两个问题 一.首先编写被调用的类,这次使用maven工 ...

  10. SQL基础试题

    第3章  关系数据库标准语言SQL 一.选择题 1.SQL语言是                    的语言,易学习. A.过程化    B.非过程化    C.格式化    D.导航式    答案 ...