面试题学习 1- 34

2021-01-02  本文已影响0人  内蒙小猿

感谢大牛
iOS 面试 ChenYilong 推荐

小知识集锦 非常好

学习并理解 23 种设计模式 较清晰

黑幕背后的Autorelease 推荐

深入了解 runloop 推荐

iOS 多线程:『NSOperation、NSOperationQueue』详尽总结 推荐 文章底部还有 GCD 、NSThread、RunLoop 都不错

小知识集锦 推荐

https://github.com/huang303513/Design-Pattern-For-iOS

iOS 性能优化梳理

MVC,MVP 和 MVVM

iOS 阿里三面 面试题整理

TCP IP、Http、Socket的区别

iOS程序中的内存分配 栈区堆区全局区

OC最实用的runtime总结,面试、工作你看我就足够了!

iOS 面向切面编程的实现与实战案例AOP

腾讯面试

category

1.dSYM你是如何分析的?

首先获取.crash 文件、.app文件、 dSYM文件,这个三个文件获取后放在一个文件夹下。通过 symblicatecrash工具进行解析

Cocoa Operation

是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

优点

NSOperationQueue

    // 主队列
    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

    [mainQueue addOperationWithBlock:^{
        //这个block语句块在主线程中执行
        NSLog(@"mainQueue -- %@",[NSThread currentThread]);
    }];

    // 自定义队列
    NSOperationQueue*oprationQueue= [[NSOperationQueue alloc] init];

    [oprationQueue addOperationWithBlock:^{
        //这个block语句块在子线程中执行
        NSLog(@"oprationQueue --- %@",[NSThread currentThread]);
    }];

NSOperation子类

/**
* 设置 MaxConcurrentOperationCount(最大并发操作数)
*/
- (void)setMaxConcurrentOperationCount {

    // 1.创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 2.设置最大并发操作数
    queue.maxConcurrentOperationCount = 1; // 串行队列
// queue.maxConcurrentOperationCount = 2; // 并发队列
// queue.maxConcurrentOperationCount = 8; // 并发队列

    // 3.添加操作
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];
}

NSOperation 操作依赖

/**
* 操作依赖
* 使用方法:addDependency:
*/
- (void)addDependency {

    // 1.创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 2.创建操作
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作
            NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程
        }
    }];

    // 3.添加依赖
    [op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2

    // 4.添加操作到队列中
    [queue addOperation:op1];
    [queue addOperation:op2];
}

NSOperation 优先级

GCD

dispatch queue分为下面三种:

GCD概念:串行队列、并行队列、同步、异步、全局队列、主队列。

串行队列、并行队列、同步、异步四者的组合线程开启情况

同步 异步
串行队列 串行同步不会创建新的线程,是同步锁的替代方案。 会新建线程,只开一条线程。 每次使用 createDispatch 方法就会新建一条线程, 多次调用该方法,会创建多条线程,多条线程间会并行执行
并行队列 不会新建线程,依然在当前线程上 会创建新的线程,可以创建多条线程。 iOS7-SDK 时代一般是5、6条, iOS8-SDK 以后可以50、60条

串行队列中的同步与异步的区别

// 串行队列
// dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL); 也是串行的
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);

    dispatch_sync(serialQueue, ^{
        NSLog(@"1");
    });
    NSLog(@"2");
    dispatch_sync(serialQueue, ^{
        NSLog(@"3");
    });
    NSLog(@"4");

    打印结果:1234
    NOTE: 顺序执行
// 并行队列
    dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(serialQueue, ^{
        NSLog(@"1");
    });
    NSLog(@"2");
    dispatch_async(serialQueue, ^{
        NSLog(@"3");
    });
    NSLog(@"4");

    打印结果:2413 、 2143 、 1234 ,但有一点是可以确认的: 1 总是在 3 之前, 2 在 4 之前。
    NOTE: 非顺序执行

3.单利的弊端

优点

缺点

在实现了 - (instancetype)allocWithZone:(struct _NSZone *)zone 并返回单例对象的前提下

4.介绍下App启动的完成过程

5.APP启动方法加载顺序

6.静态库和动态库的区别

7.APP启动慢可能是那些原因,那些因素影响启动

1.APP启动过程

戴铭 滴滴

2.影响启动性能的原因

解决方案:

1、用纯代码加载首页,而不是用 storybord。

2、didFinishLaunching 里面删除无用代码,用懒加载或者延迟加载。

3、对于 UI 无关的,比如授权 可以延迟加载。

4、对于实现了 + Load 的方法,如果可以延迟就延迟处理。

8. 0x8badf00d表示什么

看门狗超时。同步调用一个网络请求,造成主线程阻塞。

9.怎么防止反编译

10. 什么情况使用 weak 关键字,和 assign 的区别

使用 weak 情况

不同点

11. 怎么用 copy 关键字

12. 这个写法会出什么问题: @property (copy) NSMutableArray *array;

13.如何让自己的类能用 copy 修饰,copy 属性的 setter 方法重写

类实现 copy 修饰

需要实现 NSCopying 协议,如果对象有可变版本也要把 NSMutableCopying 协议。

copy setter方法重写

- (void)setName:(NSString *)name {
  _name = [name copy];
}

14. @property 本质是什么, ivar 、 setter、getter是如何生成并添加到这个类的

本质

​ property 在运行时本质是 objc_property_t , objc_property_t 是结构体,其包含两个变量 name (const char *name;)也就是属性名字 、 attribute (const char *attributes;)。attribute 本质 是 objc_property_attribute_t ,objc_property_attribute_t 同样也是结构体,它包含 类型、原子性、关键字(内存语义)、实例变量

属性的实现

​ 完成属性定义后,编译器会自动编写访问这些程序所需要的方法,添加到method_list,这个过程叫 "自动合成"。

​ 除了生成 setter、 getter 方法,编译器会自动像类中添加成员变量,以属性命前加下划线,添加到ivar_list,当做成员变量的名字。

​ 都完成 把属性添加到 prop_list 。

属性自定义

15. @protocol 和 category 中如何使用 @property

16. runtime 如何实现 weak

runtime 对注册的类,会进行布局。对 weak 修饰的对象放在一个 hash 表中,用 weak 属性指向的对象的内训地址 为 key , 属性的内存地址为 value 。当指向的对象引用计数为 0 时,就会 dealloc。通过 key 找到 value 并置为 nil

17. @property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?

属性关键字

18. weak属性需要在dealloc中置nil么?

19. @synthesize和@dynamic分别有什么作用?

synthesize

dynamic

20.ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

21. copy mutableCopy

对于非集合对象

对 immutable 对象进行 copy 操作,是指针复制,mutableCopy 操作时内容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。

集合对象 NSArray、NSDictionary、NSSet

集合类对象中,对 immutable 对象进行 copy,是指针复制, mutableCopy 是内容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。但是:集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。

22. @synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

合成实例变量的规则

假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

23. 什么情况下不会autosynthesis(自动合成)

24. synthesize使用场景

25. objc中向一个nil对象发送消息将会发生什么?

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。 那么,回到本题,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

26. objc中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

[obj foo];在objc编译时,会被转意为:objc_msgSend(obj, @selector(foo));

27. 报unrecognized selector的异常如何补救?

+ (BOOL)resolveInstanceMethod:(SEL)name 
{   
    NSLog(@" >> Instance resolving %@", NSStringFromSelector(name)); 

    if (name == @selector(MissMethod)) { 
        class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:"); 
        return YES; 
    } 

    return [super resolveInstanceMethod:name]; 
}
- (id)forwardingTargetForSelector:(SEL)aSelector 
{ 
    Doctor *doctor = [[Doctor alloc]init]; 
    if ([doctor respondsToSelector:aSelector]) { 
        return doctor; 
    } 
    return nil; 
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSString *sel = NSStringFromSelector(selector);

    if ([sel rangeOfString:@"set"].location == 0){
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }else{
        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    }
}
- (void)forwardInvocation:(NSInvocation *)invocation
{

    NSString *key = NSStringFromSelector([invocation selector]);

    if ([key rangeOfString:@"set"].location == 0){
        key= [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];
        NSString *obj;
        [invocation getArgument:&objatIndex:2];
        [_propertiesDict setObject:obj forKey:key];
    }else{
        NSString *obj = [_propertiesDict objectForKey:key];
        [invocation setReturnValue:&obj];
    }

}

28. 一个objc对象如何进行内存布局?(考虑有父类的情况)

29. 一个objc对象的isa的指针指向什么?有什么作用?

30. runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和对象(实例)方法)

31. 使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

32.对象销毁的时间表

33. _objc_msgForward函数是做什么的,直接调用它将会发生什么?

发送消息的流程是 通过对象的 isa 指针找到类,通过 objc_msgSend 首先在 class 的缓存表里面查找 IMP(没用缓存则初始化缓存),如果没找到则向父Class查找。如果一直没有找到则用_objc_msgForward 指针替代,最后调用。

34. 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

上一篇 下一篇

猜你喜欢

热点阅读