iOS面试现场,笔试提升题详解

如今已经不断有网友发我他们在面试中遇到的面试题,这是一位程序媛前面在面试中遇到的问题面试

面试题

前面两个过于基础,从提升题开始分享;我的看法,勿喷设计模式

持续关注:logic_楚阳,持续输出各大公司iOS面试系列文章,欢迎广大程序猿找我投稿面试中碰到的面试题,我会给你一份个人看法和答案,前面已经分享100道我招聘的面试题,加入下方iOS技术交流群624212887直接获取

题一:what is purpose ofdelegates?

代理的⽬的是改变或传递控制链。容许⼀个类在某些特定时刻通知到其余类,而不须要获取到那些类的指针。能够减小框架复杂度。数组

什么是代理?缓存

代理是⼀种通⽤的设计模式,代理主要由三部分组成服务器

⼀、协议:用来指定代理双方能够作什么,必须作什么;app

2、代理:根据指定的协议,完成委托⽅须要实现的功能;框架

3、委托:根据指定的协议,指定代理去完成什么功能。函数

代理的实现流程性能

在iOS中代理的本质就是代理对象内存的传递和操做,咱们在委托类设置代理对象后,实际上只是⽤一个id类型的指针将代理对象进⾏了一个弱引⽤。委托⽅让代理方执⾏操做,其实是在委托类中向这个id类型指针指向的对象发送消息,⽽这个id类型指针指向的对象,就是代理对象。ui

代理的内存管理

使⽤代理若是声明的不对,会形成循环引⽤的问题。⼀般会⽤weak修饰,⽤strong修饰会形成循环引⽤问题,⽤assign修饰会形成crash。

代理与其余iOS中消息传递的⽅式的对⽐

通知:在iOS中由通知中⼼进⾏消息接收和消息⼴播,是⼀种⼀对多的消息传递⽅式。

代理:是⼀种通⽤的设计模式,iOS中对代理⽀持的很好,由代理对象、委托者、协议三部分组成。

Block:iOS4.0中引⼊的⼀种回调⽅法,能够将回调处理代码直接写在block代码块中,看起来逻辑清晰代码整⻬。

target action:经过将对象传递到另⼀个类中,在另⼀个类中将该对象当作target的⽅式,来调⽤该对象⽅法,从内存⻆度来讲和代理相似。

KVO:NSObject的Category-NSKeyValueObserving,经过属性监听的⽅式来监测某个值的变化,当值发⽣变化时调⽤KVO的回调⽅法。

代理与block的对⽐

  1. 多个消息传递,应该使⽤delegate。在有多个消息传递时,⽤delegate实现更合适,看起来也更清晰。block就不太好了,这个时候block反而不便于维护,⽽且看起来⾮常臃肿,很别扭。例如UIKit的UITableView中有不少代理若是都换成block实现,会⽐比delegates难⽤好多。

2.一个委托对象的代理属性只能有⼀个代理对象,若是想要委托对象调⽤多个代理对象的回调应该用block。

3.单例对象最好不要⽤delegate。单例对象因为始终都只是同⼀个对象,若是使⽤delegate,就会形成delegate属性被从新赋值的问题,最终只能有一个对象能够正常响应代理⽅法。

4.代理更加⾯相过程,block则更面向结果。从设计模式的角度来讲,代理更加面向过程,⽽block更加⾯向结果。

5.从性能上来讲,block的性能消耗要略大于delegate,由于block会涉及到栈区向堆区拷⻉等操做,时间和空间上的消耗都⼤于代理。⽽代理只是定义了⼀个⽅法列表,在遵照协议对象的objc_protocol_list中添加⼀个节点,在运⾏时向遵照协议的对象发送消息便可

题二:Objective C中多重继承的实现机制。

什么是多继承?

假设C类要同时继承A类和B类,则称之为多继承。这种状况就是多继承。

oc中的“多继承”

其实Objective-C不支持多继承,因为消息机制名字查找发⽣在运⾏时⽽非编译时,很难解决多个基类可能致使的⼆义性问题。不过其实Objective-C 也⽆需⽀持多继承,咱们能够找到以下⼏种间接实现多继承⽬的方法:

  1. 经过组合实现“多继承”

  2. 经过协议实现“多继承”

经过组合实现“多继承”

图片描述

经过协议实现“多继承”

虽然OC在语法上禁⽌类使⽤多继承,可是却能够⽤协议来实现多继承。协议只能提供接⼝,而没有提供实现⽅式,若是只是想多继承基类的接⼝,那么遵照多协议⽆疑是最好的⽅法。

此⽅法缺点⽐较明显:须要修改两个⽗类,同时并不能调⽤两个⽗类的原⽣⽅法,须要在⼦类中实现⽅法。

图片描述

题三:简述Singleton的概念及并使用Objective C 写出相关代码。

Singleton: 单例模式。 简单来讲, 就是保证在你不主动销毁这个单例对象的状况下, 整个项目中都始终拥有这

个单例对象, 而且这个单例对象在内存中都是同一个内存地址。

因此, 单例很重要的两个特色:

(1) app生命周期中一直存在(除主动销毁外)

(2) 在整个生命周期中, 都是同一个内存地址

根据这两个特色, 我来描述一个应用中的使用场景。 最简单和经常使用的就是, 咱们用户的登陆信息, 不作本地缓存的话, 咱们登陆成功以后, 把服务器请求下来的用户信息保存到单例中。 好比这样 [UserSingletonshareInstance].name = “张山”。 接下来, 你不管在应用的任何页面均可以直接经过[UserSingleton shareInstance].name的方式获取到用户的名字, 并且这个名字都是”张三”。 其余作法,都会比这个麻烦。

那么怎么写单例呢? 核心的一点就是, 咱们平时建立一个实例对象时候用到的方法(alloc, init), 都要重写一遍,保证使用这些方法建立对象的时候是只分配一块内存地址,而后第一次建立以后再建立都指向前边已经建立过得那个内存地址,顺着这个思路,代码以下:

#import "Singleton.h" @interface Singleton()<NSCopying,NSMutableCopying> @end @implementation Singleton static Singleton* _instance = nil; +(instancetype) shareInstance {     static dispatch_once_t onceToken ;     dispatch_once(&onceToken, ^{         _instance = [[super allocWithZone:NULL] init] ;         //不是使用alloc方法,而是调用[[super allocWithZone:NULL] init]         //已经重载allocWithZone基本的对象分配方法,因此要借用父类(NSObject)的功能来帮助出处理底层内存分配的杂物     }) ;  return _instance ; } +(id) allocWithZone:(struct _NSZone *)zone {     return [Singleton shareInstance] ; } -(id) copyWithZone:(NSZone *)zone {     return [Singleton shareInstance] ;//return _instance; } -(id) mutablecopyWithZone:(NSZone *)zone {     return [Singleton shareInstance] ; } @end

而后,OC有个语法糖能够写:

#import "Manager.h" @implementation Manager +(Manager *)sharedManager{     static dispatch_once_t predicate;     static Manager * sharedManager;     dispatch_once(&predicate, ^{         sharedManager=[[Manager alloc] init];     });     return sharedManager; } @end

题四:简述@selector的做用

Selector/SEL又叫方法选择器,SEL在objc.h中是这样声明的,而“@selector()”是取得一个SEL指针。说白了,方法选择器仅仅是一个char *指针,表示它所表明的是方法的名字。 简单来讲: “@Selector 就是用字符串表示某个类的某个方法。” 更加专业的说法是: “Selector就是OC的虚拟表(virtual table)中指向实际执行的函数指针(function pointer)的一个C字符。”

咱们通常用它来“由于method能够用字符串表示,所以,某个method就能够变成用来传递的参数。” 再说的透明一点, 由于 selector 能够看作是函数的另外一个名字,因此不少须要调用函数或者创建链接的地方,均可以用到,如下是一些具体的使用场景:

  • Target/Action 模式

  • 检查 method 是否存在

  • Timer

  • 在线程中执行方法

  • 数组排序

  • 代替 if else / switch

  • 调用私有 API

相关文章
相关标签/搜索