1. 笔试题
0.姓名?日期。
1.C语言实现字符串反转:void reverse(char *str, int length) {}
1 | void reverse(char *str, int length) { |
2.实现一个字符串数组去重函数。
1 | var str_arr = ["b","c",1,"a", 3,"v", "2","e", "6","g", "9", "arr",9, "hello",",6", "9", "1", 2, 6, "b", "c"]; |
3.描述OC中对象的实现原理。
1 | @interface NSObject { |
NSObject对象内部存放了一个名叫isa
的指针,指向了一个结构体struct objc_class
一个NSObject对象占用多少内存?
1)系统分配了16字节给NSObject对象(通过malloc_size
函数可以获得)
2)NSObject对象内部只使用了8个字节的空间,用来存放isa
指针变量(64位系统下,可以通过class_getInstanceSize
函数获得)
4.编写代码,实现 NSObject 中添加一个属性 p1
1 | @interface NSObject (TestProperty) |
5.KVO 的实现原理和注意事项。
1) 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
2) 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
1 | willChangeValueForKey: |
注意事项:需要调用set方法触发KVO
6.下面的代码有哪些问题?
1 | @interface Demo : NSObject |
BOOL p1不应该带*。
self.p2 = p2; 调用set方法死循环。
p1没有set方法。
p2最好用copy修饰。
7.JS 和 Native 的通讯方式。
方法一:拦截URL
方法二:注册OC与JS方法
1 | - (void)webViewDidFinishLoad:(UIWebView *)webView { |
方法三:桥接机制
OC和JS交互的桥接机制,主要包含3个类,JS端window.WebViewJavascriptBridge,OC端WebViewJavascriptBridge和WebViewJavascriptBridgeBase。
桥接类支持JS调用OC方法,OC调用JS方法。JS调用OC通过重定向url并取handlerName来调用,OC调用JS通过stringByEvaluatingJavaScriptFromString调用。
8.网络5层模型是哪5层?
应用层、传输层、网络层、数据链路层、物理层
9.把t1表中 name 为 mike 的记录中 status 值改为1
1 | update t1 set status = 1 where name = mike |
10.常用的 Linux 命令。
cd 进入指定的目录
cd .. 返回上一级目录
ls 查看当前目录下的所有的目录与文件名
touch filename 表示创建一个文件
mkdir dirname 表示创建一个目录
rm filename 表示删除一个文件
rm -rf dirname 表示删除该目录及其所有的子级目录一起删掉
ctrl+c 强制终止,不会终止进程
sudo 以管理员身份运行上一个命令
:q 退出
:q! 强制退出
:wq 保存并退出
11.用过的包/库管理工具。
CocoaPods
2. 一面
1、说一下你觉得项目中遇到了什么印象深刻的问题,你是怎么解决的?
2、大学里学了哪些课?信息管理与信息系统专业是哪个学院的?
3、项目里的网络请求用到了网络5层模型的哪些,TCP/IP 属于哪一层?HTTP 呢?
TCP/IP属于传输层
HTTP属于应用层
4、你觉得自己是什么级别的?优势和不足主要是哪方面?
5、GCD 平时项目里怎么用的?
dispatch_get_mainQueue:获取主线程
dispatch_sync:同步操作
dispatch_group:线程同步
dispatch_barrier:多读单写
dispatch_semaphore:加锁,控制并发数
dispatch_once:只执行一次
dispatch_after:延时执行
6、为什么操作 UI 需要在主线程?
因为UIKit不是线程安全的。
如果不在主线程中操作UI,可能会造成如下的情况:
(1)两个线程同时设置同一个背景图片,那么很有可能因为当前图片被释放了两次而导致应用崩溃。
(2)两个线程同时设置同一个UIView的背景颜色,那么很有可能渲染显示的是颜色A,而此时在UIView逻辑树上的背景颜色属性为B。
(3)两个线程同时操作view的树形结构:在线程A中for循环遍历并操作当前View的所有subView,然后此时线程B中将某个subView直接删除,这就导致了错乱还可能导致应用崩溃。
虽然,iOS4之后苹果将大部分绘图的方法和诸如 UIColor 和 UIFont 这样的类改写为了线程安全可用,但是仍然强烈建议将UI操作保证在主线程中执行。
7、哪些是你独立开发的项目?
8、问了一下上家公司的情况
9、之后有什么打算?
10、上家薪资多少?你还有啥想问的吗?
3. 二面
1、自定义封装控件需要注意什么?有什么规范?
- 头文件尽量不要过多引入其他的类,解耦合
- 如果使用了第三方框架, 不要在头文件引入改类 切记, 不要暴露第三方组件的任何属性,枚举等等
- 定义该类的常量,方便修改
- 尽量不要引入其他项目中的类,除了一些必要的分类,业务类尽量不要引入
Frame
布局 使用分类UIView+Helper
- 尽量不要暴露成员变量或者属性,除非有必要, 其余情况最好提供接口进行操作. 注意属性的可读。
- 封装的工具类 注意如果是分类可以实现的尽量迁移到分类中, 并且命名 最好以
dd_
开头, 例如-(void)dd_layoutWithDirection:(DDImageDirection)imageDirection
,之所以这样是因为,OC没有命名空间,后加载的分类可以覆盖掉前面的同名方法. 而且一旦和系统方法重名将造成巨大的bug
- 注意 驼峰命名原则,类,协议,代理属性,命名首字母大写,最好添加
DD
类前缀
2、说一下你了解的设计模式。
设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
设计模式
装饰模式、工厂模式、单例模式、观察者模式、备忘录模式。
3、数据库怎么优化?我说数据量大的话加索引提升查询效率。问其他优化呢?比如数据库大小有没有做过优化?
(1)根据服务层面:配置mysql性能优化参数;
(2)从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等。
(3)从数据库层面增强性能:优化SQL语句,合理使用字段索引。
(4)从代码层面增强性能:使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力。
(5)减少数据库操作次数,尽量使用数据库访问驱动的批处理方法。
(6)不常使用的数据迁移备份,避免每次都在海量数据中去检索。
(7)提升数据库服务器硬件配置,或者搭建数据库集群。
(8)编程手段防止SQL注入:使用JDBC PreparedStatement按位插入或查询;正则表达式过滤(非法字符串过滤);
4、内存优化是怎么做的?什么情况会发生内存泄漏?
- 减少内存泄漏。
- 降低内存使用峰值。
- 懒加载。
- 灵活运用图片和文件加载。
- 拉长文件处理机制,逐步处理文件。
5、App 启动时间优化?
- 将一些耗时操作延迟执行。比如SDK的初始化,界面的创建。
- 不能延迟执行的,尽量放到后台执行。比如数据读取,原始 JSON 数据转对象,日志发送。
- 减少动态库、合并动态库,定期清理不必要的动态库。
- 减少类、分类的数量,合并Category和功能类似的类。删除不必要的方法和类、分类。
- 将不必须在+load中做的事延时到+initialize中。
6、视图做过哪些优化,我提了 TableView。那就以 TableView 说一下优化了哪些方面?
- cell复用,header、footer复用。
- 尽量把view设置不透明。
- 减少视图的层级。
- 尽量避免调整视图层次、添加和移除视图。
- 合理选择加载图片的方式,UIImage imageNamed: ImageAssets 用于多个地方重复使用,UIImage imageWithContentsOfFile 一般用在图片数据很大,一般不需要多次使用的情况。
- 图片大小最好和UIImageView的大小相同。
- 不要阻塞主线程,耗时操作放在子线程进行。
- 懒加载。
- 缓存,缓存图片SDWebImage,缓存行高,NSCache缓存。
- 复用高开销对象NSDateFormatter和NSCalendar。
- 减少离屏渲染,优化圆角、阴影。
- 使用正确的数据存储。