面试总结

软件架构:

按功能有mvc mvvm ,按照称此 有数据层,逻辑层,展示层

iOS9新特性

  • 临时开启后台定位

  • iOS9新加了实时交通

  • WKWebView

  • UIAlertView 过期 iOS9使用UIAlertController

  • Multitasking (多任务视图) (使用Size Class进行布局来支持)

    • 临时调出的滑动覆盖
    • 视频播放的画中画模式
    • 以及真正的同时两个app的分割视图
  • MPMoviePlayerCoontroller 过时 (不在继续维护),使用AVKit 中的AVPlayerViewController

  • watchOS 2

  • UI Test

  • Swift 2

性能优化

  1. cell重用
  2. view尽量不要透明 透明控件渲染耗费的性能较大 设置opaque(不透明)为YES (原因:如果是不透明的,就不用考虑底下的视图,如果是透明的,则需要考虑透明view底下的view)
  3. 异步加载网络数据
  4. 不要在cellForRow...中绑定数据,在willDisplay�Cells中绑定数据
  5. 尽量减少cell中控件的数量
  6. 尽量少用 addSubview 给cell 动态添加view,可以初始化时就添加,然后通过 hidden 控制显示
  7. 在 heightForRowAtIndexPath: 中尽量不要使用 cellForRowAtIndexPath: (因为heightForRowAtIndexPath调用的次数很频繁)
  8. 提前计算并缓存好高度,因为heightForRowAtIndexPath:是调用最频繁的方法之一,一定不要使用自动计算行高
  9. 滑动时按需加载,这个在大量图片展示,网络加载的时候很管用,目前的第三方框架都处理的很好了。

自己添加的view会比系统的view要小 性能会更高

设置图片 可以用画上去

内存优化

用SDWebImage加载jif格式文件时会在内存中缓存图片,改用YYWebImage 问题解决。由于SD是把Gif中的图片帧存放到数组,再进行播放,而YY加载一张播放一张释放一张

1、Analyze,静态分析内存泄露的方法。很简单,在Xcode菜单栏中点击 ”Product“ -> "Analyze",编译完成后项目工程中可能造成内存泄露的代码就会被标记出来,这样我们就可以有针对性的更改代码优化内存了。

2、使用Xcode的自带工具Leaks,动态的检测内存泄露。
1>在Xcode菜单栏中点击 ”Product“ -> "Profile"(如图1-1),弹出instruments窗口如图1-2
2>在instruments窗口中点击 ”Leaks“(如图1-2),一般Leaks就开始自动检测项目内存泄露的地方了,在此过程中可以对手机上运行的测试工程进行操作,如图1-3,Leaks 后出现的红色 柱形表示有内存泄露。
3>双击如图1-4中出现类名,就会显示出此类此方法中造成内存泄露的代码了如图1-5,然后我们就可以有针对性的优化代码、优化内存了。

Instruments

  • 使用 Allocations 来检测内存和堆栈信息
  • 使用 Leaks 检测内存的使用情况,包括内存泄露问题
  • 使用 Zombies 来检测过早释放的僵尸对象,通过它可以检测出在哪里崩溃的(image lookup -a <崩溃地址>)
  • 使用 Time Profiler 来检测 CPU 内存使用情况

将来是怎么规划的?

答:三年达到技术总监的水平
(技术总监需要做什么?:1.技术过硬 2.沟通交流,带领团队...)

为什么离开上家公司?

业务单一,想要更大的提升空间,

工作中遇到的难题?

1> block为空的时候,调用该block程序会崩溃(Crush)

2> 利用tableView的headerViewForSection:方法获取headerView时一直是nil。原因应该是设置headerView时利用- (UIView *)tableView: viewForHeaderInSection:的代理方法返回的UIView应该是UITableViewHeaderFooterView类型的,很多时候被他的返回值(UIView *)误导了。

3> 项目中需要用到循环刷新数据,利用NSTimer来实现,但是想在VC销毁时停掉timer(就是在dealloc方法中停掉),结果发现dealloc根本不调用,原本以为是引用计数没有减到0,可是问题不在此,而就在NSTimer这。结果在viewDidDisappear:停掉timer后就调用dealloc方法了。

4> 利用viewWithTag:寻找子View时,出现绝对性的错误,对象类型都不对。问题出现在设置的tag有重复,要注意的是子View在包括子View的子View的tag都不可以重复,所以建议另外创建一个文件专门设定tag,就像android中的R.java文件一样来确保tag的唯一。

5> JS交互时,由于 JavaScriptCore 存在作用域问题 有时会获取不到 Web 中的元素。

6> (低级错误)请求数据的时候,参数写错(由于参数都是字符串,没有提示,容易写错)

堆和栈的区别?

管理方式:
对于栈来讲,是由编译器自动管理,无需我们手工控制;
对于堆来说,释放工作是由程序员控制。(现在ARC情况,不需要手动管理内存)

地址分配:
栈是向低地址扩展(地址由高向低分配)的数据结构,是一块连续的内存的区域。
堆是想高地址扩展(地址由低向高分配)的数据结构,是不连续的内存区域。(这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址)

分配方式:
栈有两种分配方式:静态分配和动态分配。静态分配是由编译器完成的,如局部变量的分配。动态分配由alloca函数进行分配。
堆都是动态分配的,没有静态分配的堆。

进程和线程的区别?

进程:“正在运行”的应用程序(app),就是一个进程。
进程为应用程序开辟一块独立的内存空间。(这块内存空间是受保护的,进程和进程之间是互不干扰的)

线程:线程执行进程(应用程序)中的代码。
线程是CPU调度的最小单元。

进程和线程的关系:
每一个应用程序启动之后,都会默认/自动生成一条线程。
进程是由一个或多个线程组成的,每条线程都可以执行不同的代码。

线程并不是越多越好,原因:
(1)开启线程需要消耗一定的内存(默认情况下,一个线程占用512KB的栈区空间)
(2)会使应用程序增加很多代码。代码变多之后,程序的复杂性就会提高。
(3)CPU在多条线程之间来回切换,线程越到,CPU的负担就越大

建议:在移动应用的开发中,一般只开3~5条线程。

XML和JSON解析?

  • XML解析:

    • 方式一:(框架GDataXML)
      DOM的方式解析是将XML文档一次性加载到内存中,再进行解析。
      用DOM的方式解析XML需要用到第三方框架 GDataXML
    • 方式二:(苹果自带)
      SAX方式解析XML文档:方式:将XML文档一行一行逐行进行解析。需要设置代理,使用代理方法
  • JSON解析:(苹果自带)

    • NSJSONSerialization :JSON 解析器,可以直接将标准的JSON 数据解析成 OC 数据。
      根据JSON最外层的类型来判断是用数组还是用字典来接收。
      [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

IT社区

  • DevDiv:移动开发社区
  • 博客园
  • CSDN
  • cocoachina
  • code4app
  • 51CTO.com:IT技术网站,是一个为CTO、IT技术经理、开发工程师、项目管理人员...
  • mobilehub (漠河):里边包含了设计、开发、测试、运营等模块,各模块中包含很多其他相关的网站

学习网站

  • w3school:各种语言,手册
  • objccn (objc中国):一些分享文章

算法

排序算法:

  • 简单排序
    • 冒泡排序
    • 选择排序
    • 插入排序
      • 直接插入排序
      • 折半插入排序(二分插入排序)
  • 快速排序,(常见)
  • 堆排序
  • 归并排序,(最稳定的,即没有太差的情况)
直接插入排序

直接插入排序:基本思想:把待排序的纪录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的纪录插入完为止,得到一个新的有序序列。

直接插入排序的算法思路
(1) 设置监视哨r[0],将待插入纪录的值赋值给r[0];
(2) 设置开始查找的位置j;
(3) 在数组中进行搜索,搜索中将第j个纪录后移,直至r[0].key≥r[j].key为止;
(4) 将r[0]插入r[j+1]的位置上。

折半插入

折半插入:执行折半插入排序的前提是文件纪录必须按顺序存储。

希尔排序法

希尔排序法:先选定一个整数,把待排序文件中所有记录分成个组,并对每一组内的记录进行排序,重复上述分组和排序的工作。

堆排序

堆排序:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

归并排序

归并排序:是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

查找算法

1> 顺序查找

2> 二分查找又称折半查找,它是一种效率较高的查找方法。
【二分查找要求】:1.必须采用顺序存储结构2.必须按关键字大小有序排列。
【优缺点】折半查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

3> 分块查找:
方法描述:将n个数据元素"按块有序"划分为m块(m ≤ n)。每一块中的结点不必有序,但块与块之间必须"按块有序";即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,……。
操作步骤:
  step1 先选取各块中的最大关键字构成一个索引表;
  step2 查找分两个部分:先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;然后,在已确定的块中用顺序法进行查找。

4> 哈希表查找:设计一个函数(哈希函数, 也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标)相对应,于是用这个数组单元来存储这个元素


数据结构

常用结构:数组、链表、堆、栈、队列、树、图、散列表

是一种特殊的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆

:是由结点的有穷集合V(点)和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

散列表

若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数(Hash function),按这个思想建立的表为散列表。

基本算法的思想

回溯:

回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”(状态)都试探过。这种不断“前进”、不断“回溯”寻找解的方法,就称作“回溯法”。

递归:

递归,就是在运行的过程中调用自己。
构成递归需要具备的条件:

  1. 子问题必须与原始问题做同样的事,且更加简单。
  2. 不能无限制的调用本身,必须有个出口,化简为非递归的状态处理。

贪心:

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

分治:

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。
例:给你一个装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。找出伪币。

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