滴滴出行面试题及答案

滴滴出行面试题及答案

滴滴出行面试题

1. 笔试题

0.姓名?日期。

1.C语言实现字符串反转:void reverse(char *str, int length) {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void reverse(char *str, int length) {
char *start, *end, t;
start = str;
end = &str[length - 1];
while(start < end) {
t = *start;
*start = *end;
*end = t;
start++;
end--;
}
for (int i = 0; str[i]; i++) {
printf("%c",str[i]);
}
}

2.实现一个字符串数组去重函数。

1
2
3
4
5
6
7
8
9
10
11
12
var str_arr = ["b","c",1,"a", 3,"v", "2","e", "6","g", "9", "arr",9, "hello",",6", "9", "1", 2, 6, "b", "c"];
function unique(arr) {
var map = {}, array = [];
for (var i = 0; i < arr.length; i++) {
var key = arr[i] + typeof arr[i];
if (map[key] == null) {
map[key] = true;
array.push(arr[i]);
}
}
return array;
}

3.描述OC中对象的实现原理。

1
2
3
4
5
@interface NSObject {
Class isa;
}
@end
typedef struct objc_class *Class;

NSObject对象内部存放了一个名叫isa的指针,指向了一个结构体struct objc_class

一个NSObject对象占用多少内存?
1)系统分配了16字节给NSObject对象(通过malloc_size函数可以获得)
2)NSObject对象内部只使用了8个字节的空间,用来存放isa指针变量(64位系统下,可以通过class_getInstanceSize函数获得)

4.编写代码,实现 NSObject 中添加一个属性 p1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@interface NSObject (TestProperty)

@property (nonatomic, copy) NSString *p1;

@end

#import "NSObject+TestProperty.h"
#import <objc/runtime.h>

@implementation NSObject (TestProperty)

- (void)setP1:(NSString *)p1 {

objc_setAssociatedObject(self, @selector(p1), p1, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)p1 {

objc_getAssociatedObject(self, @selector(p1));
}

@end

5.KVO 的实现原理和注意事项。

1) 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
2) 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数

1
2
3
4
willChangeValueForKey:
父类原来的setter
didChangeValueForKey:
内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)

注意事项:需要调用set方法触发KVO

6.下面的代码有哪些问题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface Demo : NSObject
@property (nonatomic, assign) BOOL *p1;
@property (nonatomic, strong) NSString *p2;
@end

@implementation Demo
@dynamic p1;

- (void)setP2:(NSString *)p2;
{
self.p1 = YES;
self.p2 = p2;
}

@end

BOOL p1不应该带*。

self.p2 = p2; 调用set方法死循环。

p1没有set方法。

p2最好用copy修饰。

7.JS 和 Native 的通讯方式。

方法一:拦截URL

方法二:注册OC与JS方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- (void)webViewDidFinishLoad:(UIWebView *)webView {

    // 获取当前网页的标题    NSString *titleStr = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    NSLog(@"%@",titleStr);

    // 还可以直接调用js定义的方法    // 比如getShareUrl()为js端定义好的方法,返回值为分享的url    // 我们就可以通过调用这个方法在returnStr中拿到js返回的分享地址    

NSString *returnStr = [webView stringByEvaluatingJavaScriptFromString:@"getShareUrl()"];

    NSLog(@"%@",returnStr);

    // 还可以为js端提供完整的原生方法供其调用(记得导入#import )   

 JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    // 可以定义供js调用的方法, testMethod为js调用的方法名    

context[@"testMethod"] = ^() {

        dispatch_async(dispatch_get_main_queue(), ^{

            UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"" message:@"js调用方法" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil];

            [alert show];

        });
    };

方法三:桥接机制

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、内存优化是怎么做的?什么情况会发生内存泄漏?

  1. 减少内存泄漏。
  2. 降低内存使用峰值。
    • 懒加载。
    • 灵活运用图片和文件加载。
    • 拉长文件处理机制,逐步处理文件。

5、App 启动时间优化?

  1. 将一些耗时操作延迟执行。比如SDK的初始化,界面的创建。
  2. 不能延迟执行的,尽量放到后台执行。比如数据读取,原始 JSON 数据转对象,日志发送。
  3. 减少动态库、合并动态库,定期清理不必要的动态库。
  4. 减少类、分类的数量,合并Category和功能类似的类。删除不必要的方法和类、分类。
  5. 将不必须在+load中做的事延时到+initialize中。

6、视图做过哪些优化,我提了 TableView。那就以 TableView 说一下优化了哪些方面?

  1. cell复用,header、footer复用。
  2. 尽量把view设置不透明。
  3. 减少视图的层级。
  4. 尽量避免调整视图层次、添加和移除视图。
  5. 合理选择加载图片的方式,UIImage imageNamed: ImageAssets 用于多个地方重复使用,UIImage imageWithContentsOfFile 一般用在图片数据很大,一般不需要多次使用的情况。
  6. 图片大小最好和UIImageView的大小相同。
  7. 不要阻塞主线程,耗时操作放在子线程进行。
  8. 懒加载。
  9. 缓存,缓存图片SDWebImage,缓存行高,NSCache缓存。
  10. 复用高开销对象NSDateFormatter和NSCalendar。
  11. 减少离屏渲染,优化圆角、阴影。
  12. 使用正确的数据存储。

7、AFNetworking 内部是怎么样的一个过程?

8、你还有什么想问我的?

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×