如何介绍你的项目

项目问题

APP 项目
一般面试官在面试过程中,让求职者讲一下之前的项目,好多学生只是仅仅把自己会的这些知识点说了出来,而遇到不会的了有学生就直接回答“那个模块不是我做”,但凡回这一句话的面试都没戏。
如果按照层次划分,APP项目可分为三层:表现层(UI界面)、数据层(网络请求数据)、业务逻辑层。如何按照模块划分,APP项目可分为多个模块,iOS项目可以看看tabbar栏中的个数,是否还有侧滑,加起来即为模块数。
无论一个项目是个人开发还是团队开发,是上线还是没上线,APP整个项目的业务逻辑、自己负责的模块的详细业务逻辑、项目关键技术点、开发项目中遇到的问题,是无论如何都不会忘记的。

那么,项目应注意哪一些问题:
1)APP整个项目的业务逻辑、自己负责的模块的业务逻辑。无论项目是自己做的、还是团队开发、还是他人项目,一定搞清楚整个项目的业务逻辑,操作一下APP,搞清楚APP的业务流程,尤其注意模块间是否有数据传递,建议画图分析。
2)项目关键点。如果是项目是独立开发,那么所有的技术点都要弄明白;哪怕项目是团队开发,核心技术点也必须要掌握。比如说,选取的APP项目是电商类的,肯定要问支付;APP是社交类的,必问即时通讯;APP是信息展示类(新闻),必问数据处理。
3)项目遇到的问题及解决方案。在寻找项目遇到的问题,一定要找一个层次高的问题,不要举例项目中的小问题。可以举例一下,当时接入支付遇到问题,做加密的时候和安卓加出来不一致,网络请求不正确等。
4)适配。这里所说的适配并不是简简单单的是屏幕适配、还有版本适配iOS不同版本之间是否做过特殊处理。
5)项目版本迭代。项目版本更新,每一次更新做了哪些工作,是否新添加了功能,还是改了哪些bug。

介绍APP项目的方法
介绍项目是有一定套路的,不是说的点开APP想介绍哪儿就介绍哪儿。要有一定的逻辑性,要用一些专业术语来介绍项目。
在介绍项目的时候,可以从项目整体到模块,模块从左到右,界面从上到下的顺序一一介绍。或者从项目整体到模块,在介绍模块时,从重要、核心模块开始。在介绍项目时,要将项目整体定位、功能模块、主要技术都要介绍清楚,有一定的层次性。
以美团APP为例:
美团是一款及团购、旅游、美食、酒店、外卖、电影、生活服务集一体的综合性电商类型APP。它主要分为首页、商家、我的、更多四个模块。首页模块显示了一些当前热度较高、比较受欢迎的产品与服务;商家模块根据用户定位的位置显示周围的商家信息;我的模块中显示一些个人订单、钱包、积分等信息;更多模块中包含了APP用户偏好设置、以及常见问题处理。
此款APP是团队开发,迭代了2个版本。当时我开发了首页模块。首页模块以显示当前热度较高、比较受欢迎的产品与服务为主。在首页的最上面的导航栏中,包含了城市定位、搜索框、二维码扫描、推送消息记录(自己擅长的地方的技术要讲出来);紧接着下面是一个scrollview,里面有各类服务的选项,点击后可以进入相应的页面;再下面是……;最后面是……

1、OSX 版本、Xcode版本与iOS 版本【难度系数★】
Xcode自从5.0版本之后,支持arm64
2013年9月
Xcode 5.0 iOS7
2013年3月
Xcode 5.1
2014年9月
Xcode 6.0
iOS8
2014年10月 Xcode 6.1
2015年3月 Xcode 6.2
2015年4月 Xcode 6.3
2015年7月 Xcode 6.4
2015年9月 Xcode 7
iOS9
2015年10月 Xcode 7.1
2015年12月 Xcode 7.2
2016年3月 Xcode 7.3

2、MVC设计模式是什么? 你还熟悉什么设计模式?【难度系数★】
设计模式:并不是一种新技术,而是一种编码经验,使用比如java中的接口,iphone中的协议,继承关系等基本手段,用比较成熟的逻辑去处理某一种类型的事情,总结为所谓设计模式。面向对象编程中,java已经归纳了23种设计模式。
mvc设计模式 :模型,视图,控制器,可以将整个应用程序在思想上分成三大块,对应是的数据的存储或处理,前台的显示,业务逻辑的控制。 Iphone本身的设计思想就是遵循mvc设计模式。其不属于23种设计模式范畴。
代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用.比如一个工厂生产了产品,并不想直接卖给用户,而是搞了很多代理商,用户可以直接找代理商买东西,代理商从工厂进货.常见的如QQ的自动回复就属于代理拦截,代理模式在iphone中得到广泛应用.
单例模式:说白了就是一个类不通过alloc方式创建对象,而是用一个静态方法返回这个类的对象。系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为,比如想获得[UIApplication sharedApplication];任何地方调用都可以得到 UIApplication的对象,这个对象是全局唯一的。
观察者模式: 当一个物体发生变化时,会通知所有观察这个物体的观察者让其做出反应。实现起来无非就是把所有观察者的对象给这个物体,当这个物体的发生改变,就会调用遍历所有观察者的对象调用观察者的方法从而达到通知观察者的目的。
工厂模式:
public class Factory{
public static Sample creator(int which){
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}

3、Quatrz 2D的绘图功能的三个核心概念是什么并简述其作用。【难度系数★★】
上下文:主要用于描述图形写入哪里;
路径:是在图层上绘制的内容;
状态:用于保存配置变换的值、填充和轮廓, alpha 值等

4、如何调试BAD_ACCESS错误【难度系数★★】
1. 重写object的respondsToSelector方法,现实出现EXEC_BAD_ACCESS前访问的最后一个object
2. 通过 Zombie

  1. 设置全局断点快速定位问题代码所在行
  2. Xcode 7 已经集成了BAD_ACCESS捕获功能:Address Sanitizer。 用法如下:在配置中勾选?Enable Address Sanitizer

5、lldb(gdb)常用的调试命令?【难度系数★★】
breakpoint 设置断点定位到某一个函数
n 断点指针下一步
po打印对象

6、开发者证书【难度系数★★】
证书分两种:开发者证书、发布者证书。前者开发时使用,后者发布使用
(1) 模拟器调试无需代码签名;真机调试需开发者证书代码签名;发布时需发布证书签名
(2) 代码签名需要:证书+私钥,
(3) 真机调试时要求在设备上安装描述文件(provision profile),该文件包含信息:调试者证书,
授权调试设备清单,应用ID。一个应用对应一个描述文件

7、app性能测试方式【难度系数★★★】
通过Xcode提供的工具如Instrument,测试CPU,Mermory性能。也可以适用一些开源的自动化测试工具:如Frank,KIF等。

8、如何应对APP版本升级,数据结构随之变化? 【难度系数★★★】
自己解除的Sqlite相对多一些,通常的作法是重命名旧版数据库文件->创建新版本表格->导入旧版本数据->删除旧版本表
跨版本升级的问题,数据库更新的相关操作不做合并,依次迭代更新
Core data接触不多,大部分改动都在轻量化迁移支持范围内,复杂的需要重写指定映射关系

9、如何进行内存泄露检测【难度系数★★★】
(1)Run Static Analyzer
(2)instruments
(3)在init和dealloc中打印看一下init和dealloc都会成对出现,block中调用self的属性和成员变量要加__weak 或 __block

10、有方法查看当前系统内存使用情况吗? 【难度系数★★★】
1.静态分析
通过静态分析我们可以最初步的了解到代码的一些不规范的地方或者是存在的内存泄漏,这是我们第一步对内存泄漏的检测。当然有一些警告并不是我们关心的可以略过。
2.通过instruments来检查内存泄漏
这个方法能粗略的定位我们在哪里发生了内存泄漏。方法是完成一个循环操作,如果内存增长为0就证明我们程序在该次循环操作中不存在内存泄漏,如果内存增长不为0那证明有可能存在内存泄漏,当然具体问题需要具体分析。
3.代码测试内存泄漏
在做这项工作之前我们要注意一下,在dealloc的方法中我们是否已经释放了该对象所拥有的所有对象。观察对象的生成和销毁是否配对。准确的说就是init(创建对象的方法)和dealloc是否会被成对触发(简单说来就是走一次创建对象就有走一次dealloc该对象)。
下面是自己遇到的一些比较隐秘的造成内存泄漏的情况:
1.两个对象互相拥有:也就是说对象a里面retain/addSubview了b对象,b对象同时也retain/addSubView了a对象。注意:delegate不要用retain属性,要用assign属性也会导致互相拥有。
2.有时候需要用removeFromSuperView来释放:具体说明,也许我的a对象拥有一个b对象,b对象add到了c对象上,而在我们的设计中b对象的生命周期应该和a对象相同;这时候只一句[b release]/self.b = nil是不能把b对象释放掉的(一般情况下release会使其retainCount-1,[super dealloc]会再次将所有subView的retainCount-1,而b并不是a的subView,所有最后的一次-1没有了);所以我们需要在之前加上[b removeFromSuperView]。

11、如何追踪app崩溃率,如何解决线上闪退【难度系数★★★★★】

当iOS设备上的App应用闪退时,操作系统会生成一个crash日志,保存在设备上。crash日志上有很多有用的信息,比如每个正在执行线程的完整堆栈跟踪信息和内存映像,这样就能够通过解析这些信息进而定位crash发生时的代码逻辑,从而找到App闪退的原因。通常来说,crash产生来源于两种问题:违反iOS系统规则导致的crash和App代码逻辑BUG导致的crash,下面分别对他们进行分析。

违反iOS系统规则产生crash的三种类型:

(1) 内存报警闪退

当iOS检测到内存过低时,它的VM系统会发出低内存警告通知,尝试回收一些内存;如果情况没有得到足够的改善,iOS会终止后台应用以回收更多内存;最后,如果内存还是不足,那么正在运行的应用可能会被终止掉。在Debug模式下,可以主动将客户端执行的动作逻辑写入一个log文件中,这样程序童鞋可以将内存预警的逻辑写入该log文件,当发生如下截图中的内存报警时,就是提醒当前客户端性能内存吃紧,可以通过Instruments工具中的Allocations 和 Leaks模块库来发现内存分配问题和内存泄漏问题。

(2) 响应超时
当应用程序对一些特定的事件(比如启动、挂起、恢复、结束)响应不及时,苹果的Watchdog机制会把应用程序干掉,并生成一份相应的crash日志。这些事件与下列UIApplicationDelegate方法相对应,当遇到Watchdog日志时,可以检查上图中的几个方法是否有比较重的阻塞UI的动作。

(3) 用户强制退出
一看到“用户强制退出”,首先可能想到的双击Home键,然后关闭应用程序。不过这种场景一般是不会产生crash日志的,因为双击Home键后,所有的应用程序都处于后台状态,而iOS随时都有可能关闭后台进程,当应用阻塞界面并停止响应时这种场景才会产生crash日志。这里指的“用户强制退出”场景,是稍微比较复杂点的操作:先按住电源键,直到出现“滑动关机”的界面时,再按住Home键,这时候当前应用程序会被终止掉,并且产生一份相应事件的crash日志。

常见的崩溃原因基本都是代码逻辑问题或资源问题,比如数组越界,访问野指针或者资源不存在,或资源大小写错误等。

13、APP发布的上架流程【难度系数★★★★】
1.登录应用发布网站添加应用信息;
2.下载安装发布证书;
3.选择发布证书,使用Archive编译发布包,用Xcode将代码(发布包)上传到服务器;
4.等待审核通过;
5.生成IPA:菜单栏->Product->Archive.

14、对沙盒的理解【难度系数★★★】
每个iOS应用都被限制在“沙盒”中,沙盒相当于一个加了仅主人可见权限的文件夹,及时在应用程序安装过程中,系统为每个单独的应用程序生成它的主目录和一些关键的子目录。苹果对沙盒有几条限制:
1.应用程序在自己的沙盒中运作,但是不能访问任何其他应用程序的沙盒;
2.应用之间不能共享数据,沙盒里的文件不能被复制到其他应用程序的文件夹中,也不能把其他应用文件夹复制到沙盒中;
3.苹果禁止任何读写沙盒以外的文件,禁止应用程序将内容写到沙盒以外的文件夹中;
4.沙盒目录里有三个文件夹:Documents——存储;应用程序的数据文件,存储用户数据或其他定期备份的信息;Library下有两个文件夹,Caches存储应用程序再次启动所需的信息,Preferences包含应用程序的偏好设置文件,不可在这更改偏好设置;temp存放临时文件即应用程序再次启动不需要的文件。
获取沙盒根目录的方法,有几种方法:用NSHomeDirectory获取。
获取Document路径:NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask,YES).

15、对瀑布流的理解【难度系数★★★★】
首先图片的宽度都是一样的,1.将图片等比例压缩,让图片不变形;2.计算图片最低应该摆放的位置,哪一列低就放在哪;3.进行最优排列,在ScrollView的基础上添加两个tableView,然后将之前所计算的scrollView的高度通过tableView展示出来。
如何使用两个TableView产生联动:将两个tableView的滚动事件禁止掉,最外层scrollView滚动时将两个TableView跟着滚动,并且更改contentOffset,这样产生效果滚动的两个tableView。
16、内存的使用和优化的注意事项【难度系数★★★】
1)重用问题:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews设置正确的reuseIdentifier,充分重用;
2)尽量把views设置为不透明:当opque为NO的时候,图层的半透明取决于图片和其本身合成的图层为结果,可提高性能;
3)不要使用太复杂的XIB/Storyboard:载入时就会将XIB/storyboard需要的所有资源,包括图片全部载入内存,即使未来很久才会使用。那些相比纯代码写的延迟加载,性能及内存就差了很多;
4)选择正确的数据结构:学会选择对业务场景最合适的数组结构是写出高效代码的基础。比如,数组: 有序的一组值。使用索引来查询很快,使用值查询很慢,插入/删除很慢。字典: 存储键值对,用键来查找比较快。集合: 无序的一组值,用值来查找很快,插入/删除很快。
5)gzip/zip压缩:当从服务端下载相关附件时,可以通过gzip/zip压缩后再下载,使得内存更小,下载速度也更快。
6)延迟加载:对于不应该使用的数据,使用延迟加载方式。对于不需要马上显示的视图,使用延迟加载方式。比如,网络请求失败时显示的提示界面,可能一直都不会使用到,因此应该使用延迟加载。
7)数据缓存:对于cell的行高要缓存起来,使得reload数据时,效率也极高。而对于那些网络数据,不需要每次都请求的,应该缓存起来,可以写入数据库,也可以通过plist文件存储。
8)处理内存警告:一般在基类统一处理内存警告,将相关不用资源立即释放掉
9)重用大开销对象:一些objects的初始化很慢,比如NSDateFormatter和NSCalendar,但又不可避免地需要使用它们。通常是作为属性存储起来,防止反复创建。
10)避免反复处理数据:许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服务器端和客户端使用相同的数据结构很重要;
使用Autorelease Pool:在某些循环创建临时变量处理数据时,自动释放池以保证能及时释放内存;
11)正确选择图片加载方式:详情阅读细读UIImage加载方式

17、plist文件是用来做什么的。一般用它来处理一些什么方面的问题。【难度系数★★★】
plist是iOS系统中特有的文件格式。我们常用的NSUserDefaults偏好设置实质上就是plist文件操作。plist文件是用来持久化存储数据的。

我们通常使用它来存储偏好设置,以及那些少量的、数组结构比较复杂的不适合存储数据库的数据。比如,我们要存储全国城市名称和id,那么我们要优先选择plist直接持久化存储,因为更简单。

18、在提交苹果审核时,遇到哪些问题被拒绝【难度系数★★★】
1)最常见到的就是app中有虚拟物品交易,但是不是走内购导致被拒。
2)音频类App或者使用到音频相关的app,因为版权问题而被拒
3)App出现必闪退而被拒
4)人工刷广告浏览量或者广告点击率的应用程序将会被拒绝。
5)包含空iAd广告的应用程序将会被拒绝。
6)通过蜂窝网络传输的音频流内容每5分钟不得超过5MB。
7)主要功能为报时的Watch app将会被拒。(2015.4 新增)
8)只是简单的网页剪切、内容整合或者收集链接的应用程序可能会被拒绝。
9) 在未经用户事先许可,或未告知用户如何使用信息以及在何处使用信息的情况下,应用程序不能传输用户数据。
10)如果应用程序传送病毒、文件、计算机代码或程序,并且对APN服务的正常运行造成损害或中断,那么该程序将会被拒绝。

19、响应消息【难度系数★★★】
1xx:信息响应类,表示接收到请求并且继续处理
2xx:处理成功响应类,表示动作被成功接收、理解和接受
3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
5xx:服务端错误,服务器不能正确执行一个正确的请求;

20、熟悉CocoaPods么?能大概讲一下工作原理么?【难度系数★★★】
它会为我们创建一个工作区间,然后将所有在cocoapods中的引入的第三方库以libPods.a这样的方式引入到我们的工程中,这样就可以直接访问第三方库了。

21、你一般是怎么用Instruments的?【难度系数★★★】
使用Allocations来检测内存和堆栈信息
使用Leaks检测内存的使用情况,包括内存泄露问题
使用Zombies来检测过早释放的僵尸对象,通过它可以检测出在哪里崩溃的。
使用Time Profiler来检测CPU内存使用情况

22、你一般是如何调试Bug的?【难度系数★★★】
Bug分为测试中的Bug和线上的Bug:
线上Bug:项目使用了友盟统计,因此会有崩溃日志,通过解析dYSM可以直接定位到大部分bug崩溃之处。解决线上bug需要从主干拉一个新的分支,解决bug并测试通过后,再合并到主干,然后上线。若是多团队开发,可以将fix bug分支与其他团队最近要上线的分支集成,然后集成测试再上线。
测试Bug:根据测试所反馈的bug描述,若语义不清晰,则直接找到提bug人,操作给开发人员看,最好是可以bug复现。解决bug时,若能根据描述直接定位bug出错之处,则好处理;若无法直观定位,则根据bug类型分几种处理方式,比如崩溃的bug可以通过instruments来检测、数据显示错误的bug,则需要阅读代码一步步查看逻辑哪里写错。

  • 13
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值