面试题总结

最近一直在找工作,面试了不少公司,总结一下面试会经常遇到的问题。
  • 1. 使用过AF多图片上传吗?怎么确认图片全部上传成功了?
  • 2. 线程的优化?
  • 3. 2个排好序的数组求交集?
    运用归并排序的思想,实现这个求交集!
    #include
    using namespace std;
    void merge(int a[],int b[],int n,int m){
     int i=0,j=0;
     while(ib[j])
      {
       j++;
      }
      else i++;
     }
    }
    int main(){
        cout<<"分别输入两个数组的输入数字的个数(<100)"<>n>>m;
          int a[100];
     int b[100];
     cout<<"分别输入两个数组,每个数组都是从小到大的排列顺序!"<>a[i];
        for(int j=0;j>b[j];
         merge(a,b,n,m);
      return 0;
    }
    
  • 4. 哈希算法?
  • 5. IAP的时候怎么验证是否购买成功?
  • 6. MD5不可逆,后台是怎么识别你编码过后的链接的?

    数据库中存的是md5加密过的数据 人是看不懂的,用户输入密码后,后台程序通过用户输入的密码 进行md5加密 得到人看不懂的东西后 和数据库中的那个同样看不懂的东西做对比,如果一致 则表示通过验证。

  • 7. 先序遍历二叉树为 -+ab-cd/ef, 后序遍历二叉树为 a+bc-d-e/f, 求中序遍历二叉树的结果?

    二叉树的遍历分为:

    • 先序遍历:
      (1)访问根结点
      (2)先序遍历左子树
      (3)先序遍历右子树
    • 中序遍历:
      (1)中序遍历左子树
      (2)访问根结点
      (3)中序遍历右子树
    • 后序遍历
      (1)后续遍历左子树
      (2)后序遍历右子树
      (3)访问根结点
面试题总结_第1张图片
NBFK0}XXA9Q4_KL`T)S4_XE.jpg
  • 8. iOS程序的启动执行顺序和生命周期?
面试题总结_第2张图片
F3@CED5VQR~SB`}3A0OYW3M.jpg
  • 9. 创建对象时 alloc init 和new 的区别?
    英文详解:[http://macresearch.org/difference-between-alloc-init-and-new]
    1.在实际开发中很少会用到new,一般创建对象咱们看到的全是[[className alloc] init]
    但是并不意味着你不会接触到new,在一些代码中还是会看到[className new],
    还有去面试的时候,有时候会被问到这个问题。
    2.那么,他们两者之间到底有什么区别呢
    我们看源码:
    + new 
    { 
    id newObject = (*_alloc)((Class)self, 0); 
    Class metaClass = self->isa; 
    if (class_getVersion(metaClass) > 1) 
    return [newObject init]; 
    else 
    return newObject; 
    } 
     //而 alloc/init 像这样: 
    + alloc 
    { 
    return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
    } 
    - init 
    { 
    return self; 
    } 
    
    通过源码中我们发现,[className new]基本等同于[[className alloc] init];
    区别只在于alloc分配内存的时候使用了zone.
    这个zone是个什么东东呢?
    它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,                     
    以便于调用时消耗很少的代价,提升了程序处理速度;
    
    3.而为什么不推荐使用new?
    不知大家发现了没有:如果使用new的话,初始化方法被固定死只能调用init.
    而你想调用initXXX怎么办?没门儿!据说最初的设计是完全借鉴Smalltalk语法来的。
    传说那个时候已经有allocFromZone:这个方法,
    但是这个方法需要传个参数id myCompanion = [[TheClass allocFromZone:[self zone]] init];
    这个方法像下面这样:
    + allocFromZone:(void *) z 
    { 
    return (*_zoneAlloc)((Class)self, 0, z);  
    } 
     //后来简化为下面这个: 
    + alloc 
    { 
    return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
    } 
    
    但是,出现个问题:这个方法只是给对象分配了内存,并没有初始化实例变量。
    是不是又回到new那样的处理方式:在方法内部隐式调用init方法呢?
    后来发现“显示调用总比隐式调用要好”,所以后来就把两个方法分开了。
    
    
    概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。
    差别在于,采用new的方式只能采用默认的init方法完成初始化
    采用alloc的方式可以用其他定制的初始化方法。
    
  • 10. 什么是进程?什么是线程? 进程和线程的区别与联系?
    进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
    
    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
    
    3.通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。
    4线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定。线程的运行中需要使用计算机的内存资源和CPU。
    5线程与进程的区别归纳:
         a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
         b.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
         c.调度和切换:线程上下文切换比进程上下文切换要快得多。
         d.在多线程OS中,进程不是一个可执行的实体。
    6进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
    
  • 11. 常用的传值方式与区别?

    代理、Block、通知、KVO、

  • 12. 表的优化?
  • 13. AFNetworking 底层了解吗?
  • 14. SDWebImage 底层了解吗?图片加载原理?
    1 入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。
    
    2.进入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:.
    
    3. 先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
    
    4.SDImageCacheDelegate 回调imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。
    
    5.如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
    
    6.根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。
    
    7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。
    
    8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:。
    
    9.共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
    
    10.图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
    
    11.connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
    
    12.connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。
    
    13.图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
    
    14.在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
    
    15.imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
    
    16.通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
    
    17.将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。
    
    18.SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
    
  • 15. Runtime 了解吗?具体在项目用到了哪些技术?
    runtime 就是系统在运行时的一些机制,其中最主要的是消息机制。
    
    OC代码,最终都是转成了runtime(c语言库)的C语言实现。
    
    方法转成了runtime库里面的C语言函数,平时调方法都是转成
      objc_msgSend函数(所以说OC有个消息发送机制)
    
    runtime的多态:
      对于C语言,编译完成之后函数的调用关系就已经确定。
     OC的函数调用成为消息发送。属于动态调用过程。(在编译阶段
    OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。)。
    只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
    
    runtime常见作用:
         1).动态交换两个方法的实现
         2).动态添加属性
         3). 实现字典转模型的自动转换
         4).发送消息
         5). 动态添加方法
         6).拦截并替代方法
         7).实现NSCoding的自动归档和解档
    
  • 16. Runloop 了解吗? 定时器 在表滚动的时候为什么不执行了?

如果 timer 加入runloop的defaultMode,ScrollView在滚动的时候启动的切换了Mode模式,模式不匹配,肯定就不会继续执行了
深入理解RunLoop

  • 17. 用过哪些支付?能说的详细点吗?

微信、支付宝、银联、IAP、 自己百度

  • 18. Socket ?XMPP?有什么区别和联系?

XMPP协议实现原理介绍
Socket简介
面试中一般只要回答下面这样就可以了吧
xmpp 是 聊天框架 就像qq 微信 一样 , 用xmpp 可以开发一个 即使通讯的聊天的软件。
socket 是网络长连接 就像http 数据请求 一样 ,用socket 可以实现一个 时时的网络请求 , 比如 , 直播间列表 中 , 有一个人开直播 , 服务器就通知客户端 刷新数据。

  • 19.说说对weak的理解?

weak实现原理:
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

  • 追问的问题一 :实现weak后,为什么对象释放后会自动为nil?

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

  • 追问的问题二:当weak引用指向的对象被释放时,又是如何去处理weak指针的呢?

1、调用objc_release
2、因为对象的引用计数为0,所以执行dealloc
3、在dealloc中,调用了_objc_rootDealloc函数
4、在_objc_rootDealloc中,调用了object_dispose函数
5、调用objc_destructInstance
6、最后调用objc_clear_deallocating,详细过程如下:
a. 从weak表中获取废弃对象的地址为键值的记录
b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为 nil
c. 将weak表中该记录删除
d. 从引用计数表中删除废弃对象的地址为键值的记录

小伙伴们求答案!暂时就想到了之前面试会问到的。后续继续补充!

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