在2019年iOS面试题中看到的一些面试题,自己搜索答案将其整理放到一起。
1.我们说的Objective-C是动态运行时语言是什么意思
2.讲一下MVC和MVVM,MVP?
3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?
4.如何访问并修改一个类的私有属性
1.KVC(键值编码)
Person *p = [Person new];
//修改私有属性的值
[p setValue:@"yyMae" forKey:@"name"];
//访问私有属性的值
NSString *name = [p valueForKey:@"name"];
2.通过runtime获取或修改一个类私有属性的值
Person *p = [Person new];
// IVar是runtime声明的一个宏
unsigned int count = 0; //count记录变量的数量
// 获取类的所有属性变量
Ivar *members = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = members[i];
// 取得属性名并转成字符串类型
const char *memberName = ivar_getName(ivar);
NSLog(@"%s",memberName);
}
Ivar name = members[0];
// 修改属性值
object_setIvar(Person, name, @"yyMae");
5.objc使用什么机制管理对象内存?
引用计数,管理方式 1.MRC 2.ARC
1.block的本质是什么?一共有几种block?都是什么情况下生成的?
block的一些常用问答
2.使用系统的某些block api,是否考虑引用循环问题?
系统的某些block api中,UIView的block版本写动画时不需要考虑,但也有一些api 需要考虑:所谓“引用循环”是指双向的强引用,所以那些“单向的强引用”(block 强引用 self )没有问题,比如这些:
[UIView animateWithDuration:durationanimations:^{ [self.superviewlayoutIfNeeded]; }];
[[NSOperationQueuemainQueue]addOperationWithBlock:^{ self.someProperty= xyz; }];
[[NSNotificationCenterdefaultCenter]addObserverForName:@"someNotification"object:nilqueue:
[NSOperationQueuemainQueue]usingBlock:^(NSNotification* notification) { self.someProperty= xyz; }];
但如果你使用一些参数中可能含有 ivar 的系统 api ,如 GCD 、NSNotificationCenter就要小心一点:比如GCD 内部如果引用了 self,而且 GCD 的其他参数是 ivar,则要考虑到循环引用:
__weak__typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^{
__typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doSomethingElse];
} );
检测代码中是否存在循环引用问题,可使用 Facebook 开源的一个检测工具FBRetainCycleDetector。
1.runtime如何实现weak属性?如何实现weak变量的自动置nil?
weak 对象会放入一个 hash 表中。
用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc。
假如 weak 指向的对象内存地址是addr,那么就会以addr为键, 在这个 weak 表中搜索,找到所有以addr为键的 weak 对象,从而设置为 nil。
2.runtime如何通过selector找到对应的IMP地址?
在寻找IMP的地址时,runtime提供了两种方法
// IMP class_getMethodImplementation(Class cls, SEL name); class_getMethodImplementation(objc_getMetaClass("A"),@selector(methodName));
// IMP method_getImplementation(Method m); class_getMethodImplementation([A class],@selector(methodName));
3.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
1.不能向编译后得到的类增加实例变量
2.能向运行时创建的类中添加实例变量
解释:
1.编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,runtime会调用class_setvarlayout或class_setWeaklvarLayout来处理strong weak引用.所以不能向存在的类中添加实例变量
2.运行时创建的类是可以添加实例变量,调用class_addIvar函数.但是的在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上
4.在开发中如何使用runtime?什么应用场景?
Runtime重要知识点以及使用场景
1.isa指针?
在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针
每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。
2.类方法和实例方法有什么区别?
1、在类方法中不能调用实例方法,只能访问和自己一样的类方法,但实例方法可以访问类方法和实例方法。
2、在类方法中不能引用实例变量(用static修饰的变量),但实例方法可以引用成员变量和实例变量。
3、在类方法中不能使用super、this关键字。
4、类方法不能被覆盖,但实例方法可以被覆盖。
5、类方法的调用是:类名.类方法,而实例方法的调用必须new出一个对象,即:对象.实例方法。
3.介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?
主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。
category内部实现原理
未完待续···