在这个公司待了三年,虽然我有足够的危机感,但是并没有让我提升多少,所以我迫切的想换个工作环境,于是去了几个公司面试,有个自称是用户在三亿左右的公司,且不说用户量是真是假。问了很多混合开发的东西,弱项,可想而知有多狼狈了吧。综合几家公司的面试,写了这篇文集,有问题可以留言。谢谢。

1. 开发框架的选择:原生开发?混合开发?

1.1原生开发:在应用的性能上以及用户体验上是最好的,但是原生的可移植性较差,所以相对来说开发成本会稍微高点。

1.2H5与原生混合开发,主要的就用利用WKWebView,实现原生与H5的混合,主要利用的就是JS做一些交互(JSBridge的桥接)。如果页面需要变化量很快 或者是活动啥的,建议混合开发,可以节约成本(IOS+Android 共用一个h5界面),部署更新,升级都比较快。但是用户体验及性能上就稍微差些,而且有的也比较消耗资源。但是企业级的app 因为需要使用基础组件,如推送通知,管理,安全,分析数据同步和连接到企业的数据库,订阅等等,不同的场景下要视情况而定。

1.3其他的可以学习下RN,Flutter,我也打算学习fluter

2.如何保证app的稳定性?

在网上找了个图,大家可以参考下

iOS 调用H5交互 ios与h5交互面试题_iOS 调用H5交互

2.1 app稳定性首先考虑代码的逻辑,设计模式的选择等等。

内存问题:体现在内存泄露,内存警告方面。开发中学会使用instrument 检测内存泄露,cpu使用率(Instruments的time profile来定位并解决问题)以及启动时间(可以参考我的关于启动优化的文章)等指标,循环引用等问题。循环引用容易引起内存泄露,内存激增,进而导致Crash。常见的有Delegate,Block,NStimer

2.2 单元测试

可借助Xcode自带的单元测试,也可使用第三方框架OCMock

2.3.Crash 的监控

3.开发中如何解决耦合性?

3.1建议看下MVVM+RAC开发

3.2目前最常见的有router 这个解决方案。viewmodel 吧展示层的数据 view /model 的业务处理隔离开。中间层的业务逻辑耦合性就很高,可以通过router 解决。

4. jsbridge 桥接h5

基本就是依赖于 WKWebView,实现其代理,使用js 与OC的交互就能完成

5.音视频开发这块,音视频播放的原理是什么?

视音频技术主要是:音频技术,主要包括音视频的压缩编码技术,如果考虑到网络传输的话还要考虑到流媒体协议技术。

播放网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码音视频,音视频同步;如果是解码本地文件则不需要解协议。

解协议:因为播放视频的时候需要遵循各种流媒体协议技术(http,RTMP,MMS等),需要解析为标准的相应的封装格式数据。可以简单的理解为不同厂家对应不同的音视频格式。

解封装:就是将输入的封装格式(MP3,MP4,FLv等)的数据,分离为音频流压缩编码数据或者视频流压缩编码数据。

解码:可以简单理解为就是对数据视频进行压缩/解压缩的过程。常见的有H.26X(H.264,H.265等),MPEG等。

音视频同步:就是将解码好的是音视频通过声卡/显卡 播放出来。

6. weak 与assign 的区别?代理是什么修饰?

6.1.在ARC,weak 只能修饰对象,如果修饰基础数据类型,编译器会报错。在MRC时还没有weak 这个修饰符

6.2 assign 可以修饰对象也可以修饰基本数据类型,assign 修饰对象时会导致导致野指针问题,因为被assign修饰的对象在对象释放后,指针不会被置为nil,所以在次向对象发消息就会崩溃。但是被weak 修饰的对象则不会出现野指针的问题,当weak修饰的对象被系统回收时指针会被置为nil。再次向其发消息,不会崩溃。

6.3 通过以上我们知道代理为什么经常使用weak修饰,一是为了解决循环引用问题,二是为了防止野指针的出现。

7.分类能否添加属性?能否添加成员变量?为什么?

7.1在{ } 内直接声明 成员变量,编译器会直接报错。所以分类不能直接添加成员变量。

7.2分类是可以声明属性的,可以通过clang 编译器查看他的底层结构

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;

};

但是他只能生成set/get的声明,不能生成 set/get 方法的实现 ,所以在外部引用的时候,运行会报错。经典错误unrecognized selector sent to instance

可以使用runtime的动态添加关联对象 objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC) objc_getAssociatedObject实现。

8. 成员变量与实例变量的区别是什么?属性是什么?

iOS 调用H5交互 ios与h5交互面试题_音视频_02

iOS 调用H5交互 ios与h5交互面试题_app稳定性_03

9. 可变数组你经常使用什么修饰,能否使用copy?

可变数组使用strong修饰,不可变数组使用copy修饰

可变数组如果使用copy修饰的话,然后使其变成不可变数组,如果对数组进入增删改操作,然后发现carsh

这里涉及到 深/浅拷贝,深拷贝copy 拷贝其内存地址,浅拷贝strong 拷贝对象。

10.block 使用什么关键字修饰,为什么?block 想再其内部修改外部变量,需要怎么做,原因是什么?

10.1在MRC 下建议使用copy 修饰block,在ARC下建议使用copy/strong 修饰block

在MRC下block 的内存地址是在栈区,栈区的对象随时都会被系统回收,所以需要使用copy把它复制到堆区。

在ARC下,使用copy/strong 修饰block时,系统会对block 自动进行一个拷贝到堆区。

10.2 在ARC 下__block修饰外部变量,会将其包装成一个forwarding 指针指向自己。通过forwarding 修改内部变量的值。

11,OC Swift 混合开发,包的体积大吗?如何瘦身?

11.1 OC与Swift 混编会让你的ipa包体积增大,比如OC项目用到Swift的第三方,pod导入到工程时,会把Swift的整个库包也导入进来,导致项目至少会增加20兆左右。好在上传到appstore ,商城会进行一定的瘦身。

11.2 如何瘦身? 使用纯OC 代码代替混编。

12.  GCD原理

 大家都知道苹果的大部分东西都是不开源的,网上有大牛写了个GCD的源码,供参考,奉献上链接如下:https://github.com/apple/swift-corelibs-libdispatch 

另外GNUstep 是GNU计划之一,他们将Cocoa 的OC库重新写了一遍,虽然不是苹果正儿八经的源码但是可以作为参考,以下链接是:http://www.gnustep.org/resources/downloads.php

// 代码片段摘自libdispatch

//typedef void (^dispatch_block_t)(void);
void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
/*_dispatch_continuation_alloc 的实现
	 static inline dispatch_continuation_t
	 _dispatch_continuation_alloc(void)
	 {
	 dispatch_continuation_t dc =
	 _dispatch_continuation_alloc_cacheonly();
	 if (unlikely(!dc)) {
	 return _dispatch_continuation_alloc_from_heap();
	 }
	 return dc;
	 }
	 从(线程的私有存储,线程都是有自己的私有存储的,这些私有存储不会被其他线程所使用)中提取出一个 dispatch_continuation_t 结构
	 */

	dispatch_continuation_t dc = _dispatch_continuation_alloc();
	uintptr_t dc_flags = DISPATCH_OBJ_CONSUME_BIT;

	_dispatch_continuation_init(dc, dq, work, 0, 0, dc_flags);
	_dispatch_continuation_async(dq, dc);
}

以上我只写了GCD的dispatch_async 异步执行的入口,大家可以下载看看源码

总结:dispatch_async用链表保存所有提交的 block,然后在底层线程池(p_thread 创建)中,依次取出 block 并执行;

 dispatch_sync同步方法的实现相对来说更简单,只需要将任务压入响应的队列,并用信号量做等待;

13.http 与 https的区别?sotocket 通讯的实现原理以及其返回response的数据格式?

http:网络上使用最广泛的一种协议,是一个客户端与服务器端请求和应答的标准。用于向www服务器传输超文本到本地浏览器的一个传输协议。以明文传输,不安全。

https:简单的来说是http的安全版。在http的基础上嵌入了SSL协议。SSL是依靠证书来验证服务器的身份,并为浏览器与服务器之间的通讯进行加密。

加密解密等等三次握手自行脑补吧

socket: Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,可以理解为是编程接口,是对tcp/ip的封装。网络上的两个程序之间想要实现数据的双向传输交换(网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket)。

socket:开->读,写->关闭。socket即是一种特殊的文件。 网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

14.weak的实现原理?

weak 本身是个hash 表。key 是所指对象的地址,Value是weak 指针的地址数组(一个对象可能被多个弱指针指向)。runtime维护了一个weak表,用于存储一个对象的所有的weak指针。

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

3、释放时,调用clearDeallocating函数 首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。