iOS面试题

Socket:http://www.mamicode.com/info-detail-877996.html

WebView:https://www.jianshu.com/p/e6733fd9c069

WKWebView:https://www.jianshu.com/p/4fa8c4eb1316

DSBridge:https://github.com/wendux/DSBridge-IOS/blob/master/readme-chs.md

3.线程和进程的区别?

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

4.堆和栈的区别?

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

申请大小:

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出

分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。

5.Object-C的内存管理?

当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.

当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它.

如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.

20.iOS程序运行流程

1. 系统调用app的main函数

2. main函数调用UIApplicationMain.

3. UIApplicationMain创建shared application instance, UIApplication默认的instance.

4. UIApplicationMain读取Info.plist找到主nib文件, 加载nib,把shared application instance 设为nib的owner.

5. 通过nib文件,创建app的独立UIWindows object.

6. 通过nib,实例化了程序的AppDelegate object.

7. app内部启动结束,application:didFinishLaunchingWith- Options: 被设定成 wAppDelegate instance.

8. AppDelegate向UIWindow instance发makeKeyAndVisible消息, app界面展示给用户. app准备好接收用户的操作指令.


还有超级经典面试题,无答案!

1.内存管理的方式有哪些?

手动管理 ARC GC

2.怎样实现一个 singleton的类.给出思路

3.什么是序列化或者Acrchiving,可以用来做什么,怎样与copy结合,原理是什么?.

4.在iphone上有两件事情要做,请问是在一个线程里按顺序做效率高还是两个线程里做效率高?为什么?

5.runloop是什么?在主线程中的某个函数里调用了异步函数,怎么样block当前线程,且还能响应当前线程的timer事件,touch事件等.

6.ios平台怎么做数据的持久化?coredata和sqlite有无必然联系?coredata是一个关系型数据库吗?

7.阐述一个nil对象从interface bulider产生,到载入程序运行空间,最后被释放时所经历的生命周期.

8.notification是同步还是异步? kvo是同步还是异步?

9.notification是全进程空间的通知吗?kvo呢?

10.kvc是什么?kvo是什么?有什么特性?

11.响应者链是什么?

12.unix上进程怎么通信?

13.timer的间隔周期准吗?为什么?怎样实现一个精准的timer?

14.UIscrollVew用到了什么设计模式?还能再foundation库中找到类似的吗?

15.如果要开发一个类似eclipse的软件,支持插件结构。且开放给第三方开发。你会怎样去设计它?(大概思路)

16.C和obj-c 如何混用?

17.以下每行代码执行后,person对象的retain count分别是多少?Person *person = [[Person alloc] init]; // count 1?[person retain]; // count 2?[person release]; //count 1?[person release]; //retain count = 1;

18.ViewController 的 didReceiveMemoryWarning 是在什么时候被调用的?

19.内存出现警告时。

20.ios9新特性有那些?


美团一面

如何让一个label靠左,一个label靠右,然后右边的label能够完全显示

两个label全部使用自动布局,都不舍得固定的宽度,先设置左边的label文字并sizeToFit,然后再设置右边的label文字并sizeToFit

算法奇数排在前面,偶数排在后面

采用俩个指针,分别指向第一个位置,和最后一个位置,当前面的第一个指针遇到了偶数,并且后面一个指针遇到了奇数,那么就把这俩个指针指向的位置进行交换数据。

智力题,一个骑手送餐,ABCD商店,送给abcd四个人

kvo的实现原理

KVO 是 Objective-C 对观察者模式(Observer Pattern)的实现。也是 Cocoa Binding 的基础。当被观察对象的某个属性发生更改时,观察者对象会获得通知。

KVO是基于runtime机制实现的

当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制

如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法

键值观察通知依赖于NSObject 的两个方法:willChangeValueForKey:和didChangevlueForKey:;在一个被观察属性发生改变之前,willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而observeValueForKey:ofObject:change:context:也会被调用。

补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类

iOS面试题_第1张图片


消息调用的过程

调用方法分为调用实例方法和调用类方法,在结构体我们可以看到第一个就是一个 isa 指针,会指向类对象或者元类。

每个实例对象有个isa的指针,他指向对象的类,而类里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从元类本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。 

通过isa,就可以不断往上方去回溯自己的父类等,而方法的调用也利用了这个过程:

方法调用的过程1.在对象自己缓存的方法列表中去找要调用的方法,找到了就直接执行其实现。2.缓存里没找到,就去上面说的它的方法列表里找,找到了就执行其实现。3.还没找到,说明这个类自己没有了,就会通过isa去向其父类里执行1、2。4.如果找到了根类还没找到,那么就是没有了,会转向一个拦截调用的方法,我们可以自己在拦截调用方法里面做一些处理。5.如果没有在拦截调用里做处理,那么就会报错崩溃。 

iOS面试题_第2张图片

以上就是方法调用的过程。我们可以看到的是,所谓重写父类方法,并不是抹除了父类方法,父类的方法还是存在的,只是我们在子类里面找到了就不会再去父类里找了,是这个层面的“覆盖”。而我们熟悉的 super 调用父类的方法实现,就是告知要去调用父类实现的标识。

get和post的区别

get参数通过url传递,post放在request body中。

get请求在url中传递的参数是有长度限制的,而post没有。

get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。

get请求只能进行url编码,而post支持多种编码方式

get请求会浏览器主动cache,而post支持多种编码方式。

get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。

GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

GET产生一个TCP数据包;POST产生两个TCP数据包。

长的说:

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

http有哪些部分

http协议的请求又包含一下内容

 1,请求方法-URL-协议/版本

 2,请求头

 3,请求正文

http响应的请求又包含一下内容

 1,状态行

 2,响应头

 3,响应正文

在接受和解释请求的消息之后,服务器会返回一个http的响应消息

tcp和udp的区别

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保   证可靠交付

3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的

UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)

4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

5、TCP首部开销20字节;UDP的首部开销小,只有8个字节6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

七层模型

1、应用层

网络服务与最终用户的一个接口。

协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP

2、表示层

数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)

格式有,JPEG、ASCll、DECOIC、加密格式等

3、会话层

建立、管理、终止会话。(在五层模型里面已经合并到了应用层)

对应主机进程,指本地主机与远程主机正在进行的会话

4、传输层

定义传输数据的协议端口号,以及流控和差错校验。

协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层

5、网络层

进行逻辑地址寻址,实现不同网络之间的路径选择。

协议有:ICMP IGMP IP(IPV4 IPV6) ARP RARP

6、数据链路层

建立逻辑连接、进行硬件地址寻址、差错校验 [2]  等功能。(由底层网络定义协议)

将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。

7、物理层

建立、维护、断开物理连接。(由底层网络定义协议)

TCP/IP层级模型结构,应用层之间的协议通过逐级调用传输层(Transport layer)、网络层(Network Layer)和物理数据链路层(Physical Data Link)而可以实现应用层的应用程序通信互联。

应用层需要关心应用程序的逻辑细节,而不是数据在网络中的传输活动。应用层其下三层则处理真正的通信细节。在 Internet 整个发展过程中的所有思想和着重点都以一种称为 RFC(Request For Comments)的文档格式存在。针对每一种特定的 TCP/IP应用,有相应的 RFC [3]  文档。

一些典型的 TCP/IP 应用有 FTP、Telnet、SMTP、SNTP、REXEC、TFTP、LPD、SNMP、NFS、INETD 等。RFC 使一些基本相同的 TCP/IP 应用程序实现了标准化,从而使得不同厂家开发的应用程序可以互相通信

iOS面试题_第3张图片

美团二面

讲一讲响应链

如何通过一个view查找它所在的viewController

如何扩大view的响应范围


微信分享大图如何实现,从进程的角度

进程间的通信方式,并举例

两个进程分别指向同一个地址空间并初始化一个值,分别输出是什么

算法,判断一个字符串是否所有的大写字母都在小写字母前面

修改podfile文件后,怎么用git diff显示出修改后版本和当前版本的不同,让我来设计

程序执行的过程

如果想要删除自己的一段代码,如何删除(在程序执行的过程中删除)

用过脚本编程吗

了解前后端吗

阿里一面

属性的关键字

https://www.jianshu.com/p/8b3cf2187255

浅拷贝和深拷贝的区别

https://www.jianshu.com/p/5df570135ad2

Block的循环引用、如何解决、原理

https://blog.csdn.net/Jason_Wang_1314/article/details/44655957

三种Block

https://www.jianshu.com/p/6d6fd717390e

Block和delegate的比较

https://blog.csdn.net/vbirdbest/article/details/51878995

kvo的实现原理

Autorelease pool的实现原理

消息转发机制

线程死锁的四个条件

https://blog.csdn.net/rabbit_in_android/article/details/50530960

进程和线程的区别

https://blog.csdn.net/zhou753099943/article/details/51771220

持久化

https://www.jianshu.com/p/aa78b21296ea

事务的特征

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。

COMMIT

表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。

ROLLBACK

表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。事务的特性(ACID特性)

A:原子性(Atomicity)

事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。

B:一致性(Consistency)

事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

C:隔离性(Isolation)

一个事务的执行不能被其他事务干扰。

D:持续性/永久性(Durability)

一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。


中途还讨论了massonery的约束应该写在哪里,我说应该写在layoutSubViews,他说会调用多次,然后争论了一会儿

阿里二面

介绍项目

性能优化

https://blog.csdn.net/sinat_20940101/article/details/51906407

YYModel和AF源码

如何自己设计json转model

架构

迷之算法题

阿里三面

主要问了项目的一些东西 和给一些场景问我如何实现

自我介绍 介绍一些项目难点

主线程是相对于什么而言的

一张图片的内存占用大小是由什么决定的

索引的作用

索引的优缺点

在数组中找最小的k个数

淘宝下拉加载更多如何优化

淘宝页面发送HTTP请求的过程

介绍一下MVVM

知道哪些设计模式

头条一面

MVC的一些缺点

https://blog.csdn.net/sinat_36668474/article/details/53581583

讲一讲其它架构

你知道哪些编码方式

https://blog.csdn.net/shaobo8910/article/details/51397631

算法字符串翻转

HTTPS

多线程的方式和它们的区别

队列和线程的关系

一道线程安全的题

有哪些锁

属性的关键字

assign可以用于OC对象吗

copy和strong的区别

weak如何实现自动赋nil

为什么不可变对象要用copy

assing可以使用在对象中吗

头条二面

Pod update和pod install的区别

layoutIfNeeded和setNeedsLayout的区别

抓包工具抓取HTTPS的原理

isEquel和hash的关系

SD的源码

bitmap的结构

可变数组的实现原理

如何hook一个对象的方法,而不影响其它对象

如何避免if else

自旋锁和互斥锁的区别

头条三面

介绍项目,主要介绍自己强项一点的地方

数组cop后里面的元素会复制一份新的吗

数组的浅拷贝与深拷贝

TCP为什么是三次握手和四次挥手

https://www.jianshu.com/p/bbb6261cb13e

腾讯一面

介绍项目的网络层

为什么要使用HTTP???为什么不直接用TCP

如何保证HTTP传输到达

HTTP头部有哪些内容

讲一讲拥塞控制

MVVM如何实现绑定

block和通知的区别,分别适用什么场景

算法。连续问了好几个,都是数组,层层递进的,但是我忘了,只记得最后是找出数组中重复的数字

进程和线程的区别

程序在运行时操作系统除了分配内存空间还有什么

进程间通信的方式

如何检测应用是否卡顿

好像没多少问题了,记不太清,然后他说完了,我感觉好快,以为要挂了,就强行讲了些runloop和性能优化的东西,然后他说好了,你和下一轮面试官再说吧

腾讯二面

OC中对象的结构

多态

https://www.jianshu.com/p/26fab97c51ba

Ping是什么协议

https://www.jianshu.com/p/c717fa5696fc

知道MTU吗

TCP头部多长,IP呢

线程同步的方式

iOS中有哪些锁

MVC和MVVM的区别

了解哪些设计模式

存一个通讯录,包括增删改查,用什么数据结构

看过哪些源码,讲讲思路

两个链表找第一个相同结点

字符串旋转

找链表的倒数第k个结点

把一个链表比某个值大的放在左边,比它小的放在右边

二叉树的中序遍历,非递归

百度一面

进程和线程的区别

一个进程有哪些区

拥塞控制

进程间通信的方式

七层模型

TCP和UDP的区别

传输层和网络层分别是做什么的

UDP可以实现一对多??

算法 求数组的最长子数组

Http2.0如1.x的区别

百度二面

发送一个HTTP请求的过程

TCP是如何保证可靠的

内核态和用户态的区别

在一个10G的数据里面找出最大的100个数

讲一下我最满意的一个项目

然后讲了一下网络造成卡顿的原因

百度三面

全是问得iOS方面的问题,问得真的很细,需要基础很扎实,对各个机制真的足够理解,不然确实有点难回答。我只列举一下大概方向,这些东西也是iOS开发必须掌握的基础吧

属性的关键字方面的

内存管理方面的

多线程

各种队列

线程锁

MVVM


1.为什么说Objective-C是一门动态的语言?

1.object-c类的类型和数据变量的类型都是在运行是确定的,而不是在编译时确定。例如:多态特性,我们可以使用父类指针来指向子类对象,并且可以用来调用子类的方法。运行时(runtime)特性,我们可以动态的添加方法,或者替换方法。

2.讲一下MVC和MVVM,MVP?

MVC:简单来说就是,逻辑、试图、数据进行分层,实现解耦。

MVVM:是Model-View-ViewMode模式的简称。由视图(View)、视图模型(ViewModel)、模型(Model)三部分组成.比MVC更加释放控制器臃肿,将一部分逻辑(耗时,公共方法,网络请求等)和数据的处理等操作从控制器里面搬运到ViewModel中

MVVM的特点:

低耦合。View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

可重用性。可以把一些视图的逻辑放在ViewModel里面,让很多View重用这段视图逻辑。

独立开发。开发人员可以专注与业务逻辑和数据的开发(ViewModel)。设计人员可以专注于界面(View)的设计。

可测试性。可以针对ViewModel来对界面(View)进行测试

MVP:本小编没有接触,希望可以得到大家的帮助。可以在下面留言。

3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?

代理是使用weak来修饰的。1.使用weak是为了避免循环引用。2.当使用weak修饰的属性,当对象释放的时候,系统会对属性赋值nil,object-c有个特性就是对nil对象发送消息也就是调用方法,不会cash。

delegate:传递的是事件(even),代理可以让A对象通知B对象,我(A)发生的变化,前提B遵循了A的代理,并且实现了A的代理方法。

dataSource: 传递的是数据。如果A对象声明了数据源,当我们创建A对象的时候,我们就该实现数据源,来告诉A,他所需要的一些数据。例如:tableView数据源方法,需要告诉它,我要实现几组cell,每组cell多少行cell,实现的cell什么样式,什么内容

同样delegate和dataSource,都是可以使用require和optional来修饰的。

代理和Block的区别

相同点:代理和Block大多是我们都可以用来做倒序传值的。我们都得注意避免循环引用。不然我们去使用代理还是Block的时候,都需要判断它们是否实现

不同点:代理使用weak修饰,代理必须先声明方法。当我们调用代理的时候要判断是否已经实现。

block:使用的是copy来修饰,block保存的是一段代码,其实也就是一个函数。并且可以自动捕捉自动变量,如果想修改此自动变量,还必须使用__block修饰。

4.属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪些?@dynamic关键字和@synthesize关键字是用来做什么的?

属性是描述类的特征,也就是具备什么特性。三个部分,带下划线的成员变量,get、setter方法。

默认关键字:readwrite,assign, atomic; -- 是针对基本类型(NSInteger, BOOL, NSUInteger, int, 等)

但是针对引用类型, 默认:strong, readwrite, atomic (例如:NSString, NSArray, NSDictory等)

@dynamic :修饰的属性,其getter和setter方法编译器是不会自动帮你生成。必须自己是实现的。

@synthesize:修饰的属性,其getter和setter方法编译器是会自动帮你生成,不必自己实现。且指定与属性相对应的成员变量。

5.属性的默认关键字是什么?

默认关键字,基本数据: atomic,readwrite,assign

普通的 OC 对象: atomic,readwrite,strong

6.NSString为什么要用copy关键字,如果用strong会有什么问题?(注意:这里没有说用strong就一定不行。使用copy和strong是看情况而定的

众所周知,我们知道,可变类型(NSMutableArray,NSMutableString等)是不可边类型(NSString,NSArray等)的子类,因为多态的原因,我们可以使用不可边类型去接受可变类型。

1.当我们使用strong修饰A不可边类型的时候,并且使用B可变类型给A赋值,再去修改可变类型B值的时候,A所指向的值也会发生改变。引文strong只是让创建的对象引用计数器+1,并返回当前对象的内容地址,当我们修改B指向的内容的时候,A指向的内容也同样发生了改变,因为他们指向的内存地址是相同的,是一份内容。

2.当我们使用copy修饰A不可边类型的时候,并且使用B可变类型给A赋值,再去修改可变类型B值的时候,A所指向的值不会发生改变。因为当时用copy的修饰的时候,会拷贝一份内容出来,并且返回指针给A,当我们修改B指向的内容的时候,A指向的内容是没有发生改变的。因为A指向的内存地址和B指向的内存地址是不相同的,是两份内容

3.copy修饰不可边类型(NSString,NSArray等)的时候,且使用不可边类型进行赋值,表示浅拷贝,只拷贝一份指针,和strong修饰一样,当修饰的是可变类型(NSMutableArray,NSMutableString等)的时候,且使用可边类型进行赋值,表示深拷贝,直接拷贝新一份内容,到内存中。表示两份内容。

iOS面试题_第4张图片

image.png

7.如何令自己所写的对象具有拷贝功能?

如果想让自己的类具备copy方法,并返回不可边类型,必须遵循nscopying协议,并且实现

- (id)copyWithZone:(NSZone *)zone

如果让自己的类具备mutableCopy方法,并且放回可变类型,必须遵守NSMutableCopying,并实现- (id)mutableCopyWithZone:(nullable NSZone *)zone

注意:再此说的copy对应不可边类型和mutableCopy对应不可边类型方法,都是遵从系统规则而已。如果你想实现自己的规则,也是可以的。

8.可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合是内容复制的话,集合里面的元素也是内容复制么?

可变使用copy表示深拷贝,不可变集合类使用copy的时候是浅拷贝。

可变集合类、不可边类型使用mutablecopy表示深拷贝

当是浅拷贝的时候,容器的内容是没有复制的。如果是深拷贝的话,容器的内容都会收到一条copy消息,拷贝出新的内容,从新组成新的容器返回。

9.为什么IBOutlet修饰的UIView也适用weak关键字?

在xib或者Sb拖控件时,其实控件就加载到了父控件的subviews数组里面,进行了强引用,即使使用了weak,也不造成对象的释放。

10.nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?

nonatomic:表示非原子,不安全,但是效率高。

atomic:表示原子行,安全,但是效率低。

atomic:不能绝对保证线程的安全,当多线程同时访问的时候,会造成线程不安全。可以使用线程锁来保证线程的安全。

11.UICollectionView自定义layout如何实现?

实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:

-(CGSize)collectionViewContentSize返回collectionView的内容的尺寸-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect返回rect中的所有的元素的布局属性返回的是包含UICollectionViewLayoutAttributes的NSArrayUICollectionViewLayoutAttributes可以是cell,追加视图或装饰视    图的信息,通过不同的UICollectionViewLayoutAttributes初始化方法可以得到不同类型的UICollectionViewLayoutAttributes:  layoutAttributesForCellWithIndexPath:  layoutAttributesForSupplementaryViewOfKind:withIndexPath:layoutAttributesForDecorationViewOfKind:withIndexPath:  -(UICollectionViewLayoutAttributes)layoutAttributesForItemAtIndexPath:(NSIndexPath)indexPath返回对应于indexPath的位置的cell的布局属性-(UICollectionViewLayoutAttributes)layoutAttributesForSupplementaryViewOfKind:(NSString)kind atIndexPath:(NSIndexPath*)indexPath返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载-(UICollectionViewLayoutAttributes* )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath)indexPath返回对应于indexPath的位置的装饰视图的布局属性,如果没有装饰视图可不重载-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。

12.用StoryBoard开发界面有什么弊端?如何避免?

使用简单逻辑页面的跳转是可以使用sb的,开发比较块。

但是SB对于逻辑项目比较复杂的时候,开发起来比较慢。不适合多人合作开发;也不利于版本的梗系和后期的维护。使用sb在项目变异编译的时候,也都会直接加载到内存中,造成内存的浪费。

可以使用xib来代替,编辑复杂逻辑界面时候可以使用纯码编写。

13.进程和线程的区别?同步异步的区别?并行和并发的区别?

进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

同步:阻塞当前线程操作,不能开辟线程。

异步:不阻碍线程继续操作,可以开辟线程来执行任务。

并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

区别:并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。

14.线程间通信?

当使用dispath-async函数开辟线程执行任务的完成时,我们需要使用dispatch_async(dispatch_get_main_queue(), ^{  });函数会到主线程内刷新UI。并完成通信

15.GCD的一些常用的函数?(group,barrier,信号量,线程同步)

我们使用队列组来开辟线程时,队列组中的队列任务是并发,当所有的队列组中的所有任务完成时候,才可以调用队列组完成任务。

/**创建自己的队列*/dispatch_queue_tdispatchQueue = dispatch_queue_create("ted.queue.next", DISPATCH_QUEUE_CONCURRENT);/**创建一个队列组*/dispatch_group_t dispatchGroup = dispatch_group_create();/**将队列任务添加到队列组中*/dispatch_group_async(dispatchGroup, dispatchQueue, ^(){NSLog(@"dispatch-1");});/**将队列任务添加到队列组中*/dispatch_group_async(dispatchGroup, dispatchQueue, ^(){NSLog(@"dspatch-2");});/**队列组完成调用函数*/dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){NSLog(@"end");})

barrier:表示栅栏,当在并发队列里面使用栅栏时候,栅栏之前的并发任务开始并发执行,执行完毕后,执行栅栏内的任务,等栅栏任务执行完毕后,再并发执行栅栏后的任务。

dispatch_queue_tconcurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrentQueue, ^(){NSLog(@"dispatch-1");});dispatch_async(concurrentQueue, ^(){NSLog(@"dispatch-2");});dispatch_barrier_async(concurrentQueue, ^(){NSLog(@"dispatch-barrier"); });dispatch_async(concurrentQueue, ^(){NSLog(@"dispatch-3");});dispatch_async(concurrentQueue, ^(){NSLog(@"dispatch-4");});

信号量:Semaphore是通过‘计数’的方式来标识线程是否是等待或继续执行的。信号量

dispatch_semaphore_create(int)// 创建一个信号,并初始化信号的计数大小/* 等待信号,并且判断信号量,如果信号量计数大于等于你创建时候的信号量的计数,就可以通过,继续执行,并且将你传入的信号计数减1,

* 如果传入的信号计数小于你创建的计数,就表示等待,等待信号计数的变化

*  如果等待的时间超过你传入的时间,也会继续下面操作

*  第一个参数:semaphore 表示信号量

*  第二个参数:表示等待的时间

*    返回int 如果传入的信号计数大于等于你创建信号的计数时候,返回0.  反之,返回的不等于0

*/intresult = dispatch_semaphore_wait(dispatch_semaphore_tsemaphore,time outTime);// 表示等待,也是阻碍线程// 表示将信号技术+1dispatch_semaphore_signl(dispatch_semaphore_tsemaphore);

实现线程的同步的方法:串行队列,分组,信号量。也是可以使用并发队列。

//加入队列dispatch_async(concurrentQueue, ^{//1.先去网上下载图片dispatch_sync(concurrentQueue, ^{          });//2.在主线程展示到界面里dispatch_sync(dispatch_get_main_queue(), ^{    });});

16.如何使用队列来避免资源抢夺?

当我们使用多线程来访问同一个数据的时候,就有可能造成数据的不准确性。这个时候我么可以使用线程锁的来来绑定。也是可以使用串行队列来完成。如:fmdb就是使用FMDatabaseQueue,来解决多线程抢夺资源。

17.数据持久化的几个方案(fmdb用没用过)

持久化方案:

plist,存储字典,数组比较好用

preference:偏好设置,实质也是plist

NSKeyedArchiver:归档,可以存储对象

sqlite:数据库,经常使用第三方来操作,也就是fmdb

coreData:也是数据库储存,苹果官方的

18.说一下appdelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?

iOS面试题_第5张图片

1029210 (1).gif

19.NSCache优于NSDictionary的几点?

1.nscache 是可以自动释放内存的。

2.nscache是线程安全的,我们可以在不同的线程中添加,删除和查询缓存中的对象。

3.一个缓存对象不会拷贝key对象。

20.知不知道Designated Initializer?使用它的时候有什么需要注意的问题?

个人理解:初始化函数,如果你想自定义初始化函数时,也是必须要初始化父类,以来保证可以继承父类的一些方法或者属性。

Designated Initializer

21.实现description方法能取到什么效果?

description是nsobject的一个实例的方法,返回的是一个nsstring。当我们使用nslog打印的时候,打印出来的一般都是对象的内存地址,如果我们实现description方法时,我们就可以使用nslog打印对象的时候,我们可以把它里面的属性值和内存地址一起打印出来.打印什么,就是看你写什么了。

-(NSString*)description{NSString* string = [NSStringstringWithFormat:@"",self,self.name,self.age];returnstring;      }

22.objc使用什么机制管理对象内存?

使用内存管理计数器,来管理内存的。当内存管理计数器为0的时候,对象就会被释放。

中级

Block

1.block的实质是什么?一共有几种block?都是什么情况下生成的?

block:本质就是一个object-c对象.

block:存储位置,可能分为3个地方:代码去,堆区、栈区(ARC情况下会自动拷贝到堆区,因此ARC下只能有两个地方:代码去、堆区)

代码区:不访问栈区的变量(如局部变量),且不访问堆区的变量(alloc创建的对象),此时block存放在代码去。

堆区:访问了处于栈区的变量,或者堆区的变量,此时block存放在堆区。–需要注意实际是放在栈区,在ARC情况下会自动拷贝到堆区,如果不是ARC则存放在栈区,所在函数执行完毕就回释放,想再外面调用需要用copy指向它,这样就拷贝到了堆区,strong属性不会拷贝、会造成野指针错区。

2.为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?

默认情况下,block里面的变量,拷贝进去的是变量的值,而不是指向变量的内存的指针。

当使用__block修饰后的变量,拷贝到block里面的就是指向变量的指针,所以我们就可以修改变量的值。

3.模拟一下循环引用的一个情况?block实现界面反向传值如何实现?

Person *p = [[Person alloc]init];[p setPersonBlock:^(NSString*str) {    p.name = str;}];

Runtime

1.objc在向一个对象发送消息时,发生了什么?

根据对象的isa指针找到类对象id,在查询类对象里面的methodLists方法函数列表,如果没有在好到,在沿着superClass,寻找父类,再在父类methodLists方法列表里面查询,最终找到SEL,根据id和SEL确认IMP(指针函数),在发送消息;

3.什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?

当发送消息的时候,我们会根据类里面的methodLists列表去查询我们要动用的SEL,当查询不到的时候,我们会一直沿着父类查询,当最终查询不到的时候我们会报unrecognized selector错误

当系统查询不到方法的时候,会调用+(BOOL)resolveInstanceMethod:(SEL)sel动态解释的方法来给我一次机会来添加,调用不到的方法。或者我们可以再次使用-(id)forwardingTargetForSelector:(SEL)aSelector重定向的方法来告诉系统,该调用什么方法,一来保证不会崩溃。

4.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

1.不能向编译后得到的类增加实例变量

2.能向运行时创建的类中添加实例变量

解释:

1.编译后的类已经注册在runtime中,类结构体中的objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已经确定,runtime会调用class_setvarlayout或class_setWeaklvarLayout来处理strong weak引用.所以不能向存在的类中添加实例变量

2.运行时创建的类是可以添加实例变量,调用class_addIvar函数.但是的在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上.

5.runtime如何实现weak变量的自动置nil?

runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

6.给类添加一个属性后,在类结构体里哪些元素会发生变化?

instance_size :实例的内存大小

objc_ivar_list *ivars:属性列表

RunLoop

1.runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?

runloop:字面意思就是跑圈,其实也就是一个循环跑圈,用来处理线程里面的事件和消息。

runloop和线程的关系:每个线程如果想继续运行,不被释放,就必须有一个runloop来不停的跑圈,以来处理线程里面的各个事件和消息。

主线程默认是开启一个runloop。也就是这个runloop才能保证我们程序正常的运行。子线程是默认没有开始runloop的

2.runloop的mode是用来做什么的?有几种mode?

model:是runloop里面的模式,不同的模式下的runloop处理的事件和消息有一定的差别。

系统默认注册了5个Mode:

(1)kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。

(2)UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。

(3)UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。

(4)GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。

(5)kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。

注意iOS 对以上5中model进行了封装

NSDefaultRunLoopMode;

NSRunLoopCommonModes

3.为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?

nstime对象是在NSDefaultRunLoopMode下面调用消息的,但是当我们滑动scrollview的时候,NSDefaultRunLoopMode模式就自动切换到UITrackingRunLoopMode模式下面,却不可以继续响应nstime发送的消息。所以如果想在滑动scrollview的情况下面还调用nstime的消息,我们可以把nsrunloop的模式更改为NSRunLoopCommonModes

4.苹果是如何实现Autorelease Pool的?

Autorelease Pool作用:缓存池,可以避免我们经常写relase的一种方式。其实就是延迟release,将创建的对象,添加到最近的autoreleasePool中,等到autoreleasePool作用域结束的时候,会将里面所有的对象的引用计数器-1.

autorelease

类结构

1.isa指针?(对象的isa,类对象的isa,元类的isa都要说)

在oc中,类也是对象,所属元类。所以经常说:万物皆对象

对象的isa指针指向所属的类

类的isa指针指向了所属的元类

元类的isa指向了根元类,根元类指向了自己。

iOS面试题_第6张图片

AC17D0A0-CB2A-4C23-8430-4BC7A99571CE.png

2.类方法和实例方法有什么区别?

调用的方式不同,类方法必须使用类调用,在方法里面不能调用属性,类方法里面也必须调用类方法。存储在元类结构体里面的methodLists里面

实例方法必须使用实例对象调用,可以在实例方法里面使用属性,实例方法也必须调用实例方法。存储在类结构体里面的methodLists里面

3.介绍一下分类,能用分类做什么?内部是如何实现的?它为什么会覆盖掉原来的方法?

category:我们可以给类或者系统类添加实例方法方法。我们添加的实例方法,会被动态的添加到类结构里面的methodList列表里面。categort

4.运行时能增加成员变量么?能增加属性么?如果能,如何增加?如果不能,为什么?

可以添加属性的,但必须我们实现它的getter和setter方法。但是没有添加带下滑线同名的成员变量

但是我们使用runtime我们就可以实现添加成员变量方法如下

- (void)setName:(NSString *)name {/** *  为某个类关联某个对象 * *@paramobject#> 要关联的对象 description#> *@paramkey#>    要关联的属性key description#> *@paramvalue#>  你要关联的属性 description#> *@parampolicy#> 添加的成员变量的修饰符 description#> */objc_setAssociatedObject(self, @selector(name), name,  OBJC_ASSOCIATION_COPY_NONATOMIC);}- (NSString *)name {/** *  获取到某个类的某个关联对象 * *@paramobject#> 关联的对象 description#> *@paramkey#>    属性的key值 description#> */returnobjc_getAssociatedObject(self, @selector(name));}

5.objc中向一个nil对象发送消息将会发生什么?(返回值是对象,是标量,结构体)

• 如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如:Person * motherInlaw = [ aPerson spouse] mother]; 如果spouse对象为nil,那么发送给nil的消息mother也将返回nil。

• 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者long long的整型标量,发送给nil的消息将返回0。

• 如果方法返回值为结构体,正如在《Mac OS X ABI 函数调用指南》,发送给nil的消息将返回0。结构体中各个字段的值将都是0。其他的结构体数据类型将不是用0填充的。

• 如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。

详细解答

高级

1.UITableview的优化方法(缓存高度,异步绘制,减少层级,hide,避免离屏渲染)

缓存高度:当我们创建frame模型的时候,计算出来cell的高度的时候,我们可以将cell的高度缓存到字典里面,以cell的indexpath和Identifier作为为key。

NSString*key = [[HeightCache shareHeightCache] makeKeyWithIdentifier:@"YwywProductGradeCell"indexPath:indexPath];if([[HeightCache shareHeightCache] existInCacheByKey:key]) {return[[HeightCache shareHeightCache] heightFromCacheWithKey:key];}else{    YwywProductGradeModelFrame *modelFrame =self.gradeArray[indexPath.row];    [[HeightCache shareHeightCache] cacheHieght:modelFrame.cellHight key:key];returnmodelFrame.cellHight;}

异步绘制、减少层级:目前还不是很清楚

hide:个人理解应该是hidden吧,把可能会用到的控件都创建出来,根据不同的情况去隐藏或者显示出来。

避免离屏渲染:只要不是同时使用边框/边框颜色以及圆角的时候,都可以使用layer直接设置。不会造成离屏渲染。

2.有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)

交换方式:一般写在类的+(void)load方法里面

/** 获取原始setBackgroundColor方法 */Method originalM = class_getInstanceMethod([selfclass],@selector(setBackgroundColor:));/** 获取自定义的pb_setBackgroundColor方法 */Method exchangeM = class_getInstanceMethod([selfclass],@selector(pb_setBackgroundColor:));/** 交换方法 */method_exchangeImplementations(originalM, exchangeM);

创建类:

Class MyClass = objc_allocateClassPair([NSObjectclass],"Person",0);

添加方法

/**参数一、类名参数

  二、SEL 添加的方法名字参数

    三、IMP指针 (IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP)

  参数四、其中types参数为"i@:@“,按顺序分别表示:具体类型可参照[官方文档](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)i 返回值类型int,若是v则表示void@ 参数id(self): SEL(_cmd)@ id(str)

  V@:表示返回值是void 带有SEL参数 (An object (whether statically typed or typed id))

  */class_addMethod(Person,@selector(addMethodForMyClass:), (IMP)addMethodForMyClass,"V@:");

添加实例变量

/**参数一、类名参数

  二、属性名称参数

  三、开辟字节长度参数

  四、对其方式参数

  五、参数类型 “@” 官方解释 An object (whether statically typed or typed id) (对象 静态类型或者id类型) 具体类型可参照[官方文档](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)return: BOOL 是否添加成功

  */BOOLisSuccess = class_addIvar(Person,"name",sizeof(NSString*),0,"@");isSuccess?NSLog(@"添加变量成功"):NSLog(@"添加变量失败");

3.看过哪些第三方框架的源码?都是如何实现的?(如果没有,问一下多图下载的设计)

4.SDWebImage的缓存策略?

sd加载一张图片的时候,会先在内存里面查找是否有这张图片,如果没有会根据图片的md5(url)后的名称去沙盒里面去寻找,是否有这张图片,如果没有会开辟线程去下载,下载完毕后加载到imageview上面,并md(url)为名称缓存到沙盒里面。

5.AFN为什么添加一条常驻线程?

AFN 目的:就是开辟线程请求网络数据。如果没有常住线程的话,就会每次请求网络就去开辟线程,完成之后销毁开辟线程,这样就造成资源的浪费,开辟一条常住线程,就可以避免这种浪费,我们可以在每次的网络请求都添加到这条线程。

6.KVO的使用?实现原理?(为什么要创建子类来实现)

kvo:键值观察,根据键对应的值的变化,来调用方法。

注册观察者:addObserver:forKeyPath:options:context:

实现观察者:observeValueForKeyPath:ofObject:change:context:

移除观察者:removeObserver:forKeyPath:(对象销毁,必须移除观察者)

注意

使用kvo监听A对象的时候,监听的本质不是这个A对象,而是系统创建的一个中间对象NSKVONotifying_A并继承A对象,并且A对象的isa指针指向的也不是A的类,而是这个NSKVONotifying_A对象

kvo详解

kvo详解2

7.KVC的使用?实现原理?(KVC拿到key以后,是如何赋值的?知不知道集合操作符,能不能访问私有属性,能不能直接访问_ivar)

kvc:键值赋值,使用最多的即使字典转模型。利用runtime获取对象的所有成员变量, 在根据kvc键值赋值,进行字典转模型

setValue: forKey: 只查找本类里面的属性

setValue: forKeyPath:会查找本类里面属性,没有会继续查找父类里面属性。

kvc详解

项目

1.有已经上线的项目么?

2.项目里哪个部分是你完成的?(找一个亮点问一下如何实现的)

3.开发过程中遇到过什么困难,是如何解决的?

学习

4.遇到一个问题完全不能理解的时候,是如何帮助自己理解的?举个例子?

5.有看书的习惯么?最近看的一本是什么书?有什么心得?

6.有没有使用一些笔记软件?会在多平台同步以及多渠道采集么?(如果没有,问一下是如何复习知识的)

7.有没有使用清单类,日历类的软件?(如果没有,问一下是如何安排,计划任务的)

8.平常看博客么?有没有自己写过?(如果写,有哪些收获?如果没有写,问一下不写的原因)

你可能感兴趣的:(iOS面试题)