ios面试

线程队列关系

https://www.jianshu.com/p/abeaaf3c3dd1

main函数之前走了几步

https://www.jianshu.com/p/1d2bef8a87e4

https://www.jianshu.com/p/e6a80ebaf6bb?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

简单的回答:

1.动态库链接库

2.ImageLoader加载可执行文件, 里边是被编译过的符号,代码等

3.runtime与+load


性能优化

https://www.jianshu.com/p/fe566ec32d28

https://mp.weixin.qq.com/s/jN3jaNrvXczZoYIRCWZs7w


内存优化

内存泄露检测

https://www.jianshu.com/p/9fc2132d09c7

ios网络优化 

 https://www.jianshu.com/p/a470ab485e39

https://www.cnblogs.com/ziyi--caolu/p/8058577.html

  https://www.infoq.cn/article/how-ctrip-improves-app-networking-performance/#

synchronized  开发    https://www.cnblogs.com/feng9exe/p/7233349.html

ios 重签名机制  https://www.jianshu.com/p/47facc920fb5

http://blog.cnbang.net/tech/3386/

atomc  https://cloud.tencent.com/developer/article/1445940 为什么不是线程安全

http 原理 https://www.jianshu.com/p/14cd2c9d2cd2

性能优化  https://www.jianshu.com/p/95df83780c8f

instruments- 通过leaks分析内存泄露    性能调优工具 Instruments 之 TimeProfiler 

https://blog.csdn.net/lichuandev/article/details/79636363


Assets和文件 区别http://www.manongjc.com/article/68443.html

tcp udp  https://blog.csdn.net/wuhuagu_wuhuaguo/article/details/78507826

https://segmentfault.com/a/1190000020053709

layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer


I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)

   P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)

   B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累~


afnetwork 做了什么

http://www.cocoachina.com/articles/18277

https://www.jianshu.com/p/3506b9babdac

 https://juejin.im/post/5d1efe16f265da1baa1e944d

特别好 afnetwork 原理  https://www.jianshu.com/p/488c1f46cedd

特别好  afnetwork  https://www.jianshu.com/p/856f0e26279d

https://www.jianshu.com/p/f32bd79233da

sdwebimage

https://blog.csdn.net/jacky_jin/article/details/73312810

http://www.cocoachina.com/articles/16869

https://msd.misuland.com/pd/3107373619924174644

https://www.jianshu.com/p/b8517dc833c7

https://www.jianshu.com/p/fd02749bd44a

https://www.cnblogs.com/liuyang666/p/5288599.html

https://www.cnblogs.com/liuyang666/p/5288599.html


ios底层

  https://www.jianshu.com/notebooks/24110540

block  https://www.jianshu.com/p/a41396ff0247

categoty 后编译的执行

dispatch_once 源码http://lingyuncxb.com/2018/02/01/GCD源码分析2%20——%20dispatch-once篇/

gcd 源码 http://lingyuncxb.com/categories/iOS/

Crash 防护系统  https://www.jianshu.com/p/e3713d309283

https  https://www.jianshu.com/p/c73839a3ed18





KVC的底层实现?

当一个对象调用setValue方法时,方法内部会做以下操作:

1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。

2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。

3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。

4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。

这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。


如何高性能的给 UIImageView 加个圆角?

不好的解决方案:使用下面的方式会强制Core Animation提前渲染屏幕的离屏绘制, 而离屏绘制就会给性能带来负面影响,会有卡顿的现象出现。

self.view.layer.cornerRadius = 5.0f;

self.view.layer.masksToBounds = YES;

正确的解决方案:使用绘图技术

- (UIImage *)circleImage {

    // NO代表透明

    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);

    // 获得上下文

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 添加一个圆

    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextAddEllipseInRect(ctx, rect);

    // 裁剪

    CGContextClip(ctx);

    // 将图片画上去

    [self drawInRect:rect];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // 关闭上下文

    UIGraphicsEndImageContext();

    return image;

}

还有一种方案:使用了贝塞尔曲线"切割"个这个图片, 给UIImageView 添加了的圆角,其实也是通过绘图技术来实现的。

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

imageView.center = CGPointMake(200, 300);

UIImage *anotherImage = [UIImage imageNamed:@"image"];

UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);

[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds

                       cornerRadius:50] addClip];

[anotherImage drawInRect:imageView.bounds];

imageView.image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

[self.view addSubview:imageView];


答卓同学ios面试题

2018 iOS面试题

ios保持流畅性的技巧


1> 如果当前这个view是控制器的view,那么控制器就是上一个响应者

2> 如果当前这个view不是控制器的view,那么父控件就是上一个响应者


响应者链的事件传递过程:

1>如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图

2>在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理

3>如果window对象也不处理,则其将事件或消息传递给UIApplication对象

4>如果UIApplication也不能处理该事件或消息,则将其丢弃

事件处理的整个流程总结:

  1.触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中(即,首先接收到事件的是UIApplication)。

  2.UIApplication会从事件队列中取出最前面的事件,把事件传递给应用程序的主窗口(keyWindow)。

  3.主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。(至此,第一步已完成)

  4.最合适的view会调用自己的touches方法处理事件

  5.touches默认做法是把事件顺着响应者链条向上抛。

touches的默认做法:


备战九十 ios面试题菜单

四、RunLoop的实现机制

对于RunLoop而言最核心的事情就是保证线程在没有消息的时候休眠,在有消息时唤醒,以提高程序性能。RunLoop这个机制是依靠系统内核来完成的(苹果操作系统核心组件Darwin中的Mach)。

RunLoop通过mach_msg()函数接收、发送消息。它的本质是调用函数mach_msg_trap(),相当于是一个系统调用,会触发内核状态切换。在用户态调用 mach_msg_trap()时会切换到内核态;内核态中内核实现的mach_msg()函数会完成实际的工作。 即基于port的source1,监听端口,端口有消息就会触发回调;而source0,要手动标记为待处理和手动唤醒RunLoop

Mach消息发送机制 大致逻辑为: 1、通知观察者 RunLoop 即将启动。 2、通知观察者即将要处理Timer事件。 3、通知观察者即将要处理source0事件。 4、处理source0事件。 5、如果基于端口的源(Source1)准备好并处于等待状态,进入步骤9。 6、通知观察者线程即将进入休眠状态。 7、将线程置于休眠状态,由用户态切换到内核态,直到下面的任一事件发生才唤醒线程。

一个基于 port 的Source1 的事件(图里应该是source0)。

一个 Timer 到时间了。

RunLoop 自身的超时时间到了。

被其他调用者手动唤醒。

8、通知观察者线程将被唤醒。 9、处理唤醒时收到的事件。

如果用户定义的定时器启动,处理定时器事件并重启RunLoop。进入步骤2。

如果输入源启动,传递相应的消息。

如果RunLoop被显示唤醒而且时间还没超时,重启RunLoop。进入步骤2

10、通知观察者RunLoop结束。


1、加速启动时间。快速打开app是很重要的,特别是用户第一次打开它时,对app来讲,第一印象太太太重要了。你能做的就是使它尽可能做更多的异步任务,比如加载远端或者数据库数据,解析数据。避免过于庞大的XIB,因为他们是在主线程上加载的。所以尽量使用没有这个问题的Storyboards吧!一定要把设备从Xcode断开来测试启动速度

2、使用Autorelease Pool。NSAutoreleasePool`负责释放block中的autoreleased objects。一般情况下它会自动被UIKit调用。但是有些状况下你也需要手动去创建它。假如你创建很多临时对象,你会发现内存一直在减少直到这些对象被release的时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释放。消息是你可以在你自己的@autoreleasepool里创建临时的对象来避免这个行为。

3、选择是否缓存图片。常见的从bundle中加载图片的方式有两种,一个是用imageNamed,二是用imageWithContentsOfFile,第一种比较常见一点。

4、避免日期格式转换。如果你要用NSDateFormatter来处理很多日期格式,应该小心以待。就像先前提到的,任何时候重用NSDateFormatters都是一个好的实践。如果你可以控制你所处理的日期格式,尽量选择Unix时间戳。你可以方便地从时间戳转换到NSDate:

    - (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {

    return[NSDate dateWithTimeIntervalSince1970:timestamp];

    }


这样会比用C来解析日期字符串还快!需要注意的是,许多web API会以微秒的形式返回时间戳,因为这种格式在javascript中更方便使用。记住用dateFromUnixTimestamp之前除以1000就好了。

平时你是如何对代码进行性能优化的?

利用性能分析工具检测,包括静态 Analyze 工具,以及运行时 Profile 工具,通过Xcode工具栏中Product->Profile可以启动,

比如测试程序启动运行时间,当点击Time Profiler应用程序开始运行后.就能获取到整个应用程序运行消耗时间分布和百分比.为了保证数据分析在统一使用场景真实需要注意一定要使用真机,因为此时模拟器是运行在Mac上,而Mac上的CPU往往比iOS设备要快。

为了防止一个应用占用过多的系统资源,开发iOS的苹果工程师门设计了一个“看门狗”的机制。在不同的场景下,“看门狗”会监测应用的性能。如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者们在crashlog里面,会看到诸如0x8badf00d这样的错误代码。

优化Table View

正确使用reuseIdentifier来重用cells

尽量使所有的view opaque,包括cell自身

如果cell内现实的内容来自web,使用异步加载,缓存请求结果 减少subviews的数量

尽量不适用cellForRowAtIndexPath:,如果你需要用到它,只用一次然后缓存结果

使用rowHeight, sectionFooterHeight和sectionHeaderHeight来设定固定的高,不要请求delegate

UIImage加载图片性能问题

imagedNamed初始化

imageWithContentsOfFile初始化

imageNamed默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.如果缓存中没有找到相应的图片对象,则从指定地方加载图片然后缓存对象,并返回这个图片对象.

imageWithContentsOfFile则仅只加载图片,不缓存.

加载一张大图并且使用一次,用imageWithContentsOfFile是最好,这样CPU不需要做缓存节约时间.

使用场景需要编程时,应该根据实际应用场景加以区分,UIimage虽小,但使用元素较多问题会有所凸显.

不要在viewWillAppear 中做费时的操作:viewWillAppear: 在view显示之前被调用,出于效率考虑,方法中不要处理复杂费时操作;在该方法设置 view 的显示属性之类的简单事情,比如背景色,字体等。否则,会明显感觉到 view 有卡顿或者延迟。

在正确的地方使用reuseIdentifier:table view用 tableView:cellForRowAtIndexPath:为rows分配cells的时候,它的数据应该重用自UITableViewCell。

尽量把views设置为透明:如果你有透明的Views你应该设置它们的opaque属性为YES。系统用一个最优的方式渲染这些views。这个简单的属性在IB或者代码里都可以设定。

避免过于庞大的XIB:尽量简单的为每个Controller配置一个单独的XIB,尽可能把一个View Controller的view层次结构分散到单独的XIB中去, 当你加载一个引用了图片或者声音资源的nib时,nib加载代码会把图片和声音文件写进内存。

不要阻塞主线程:永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成,大部分阻碍主进程的情形是你的app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 选择一个子线程来执行耗时操作 dispatch_async(dispatch_get_main_queue(), ^{ // 返回主线程更新UI }); });

在Image Views中调整图片大小 如果要在UIImageView中显示一个来自bundle的图片,你应保证图片的大小和UIImageView的大小相同。在运行中缩放图片是很耗费资源的.

讲讲你用Instrument优化动画性能的经历吧(别问我什么是Instrument)

Apple的instrument为开发者提供了各种template去优化app性能和定位问题。很多公司都在赶feature,并没有充足的时间来做优化,导致不少开发者对instrument不怎么熟悉。但这里面其实涵盖了非常完整的计算机基础理论知识体系,memory,disk,network,thread,cpu,gpu等等,顺藤摸瓜去学习,是一笔巨大的知识财富。动画性能只是其中一个template,重点还是理解上面问题当中CPU GPU如何配合工作的知识。

facebook启动时间优化

1.瘦身请求依赖 2.UDP启动请求先行缓存 3.队列串行化处理启动响应



ios面试_第1张图片

多线程死锁

https://www.jianshu.com/p/0d96f03597f6

https://www.jianshu.com/p/1f1b9516c631

kvo底层实现

https://www.jianshu.com/p/d6faa91a9721

ios组件化。pod 私有库

https://www.jianshu.com/p/5b52b49d2392

https://cloud.tencent.com/developer/article/1419756


category和extension

https://www.jianshu.com/p/dc3196030a03



fhttps://www.jianshu.com/p/4546f22b2e96 

1 动态解析对象方法时,会调用+(BOOL)resolveInstanceMethod:(SEL)sel方法。

2 动态解析类方法时,会调用+(BOOL)resolveClassMethod:(SEL)sel方法。

class_addMethod 添加方法

消息转发

- (id)forwardingTargetForSelector:(SEL)aSelector

{

    // 返回能够处理消息的对象

    if (aSelector == @selector(driving)) {

        return [[Car alloc] init];

    }

    return [super forwardingTargetForSelector:aSelector];

}

@end

3消息签名

methodSignatureForSelector

如果methodSignatureForSelector方法返回正确的方法签名就会调用forwardInvocation方法,forwardInvocation方法内提供一个NSInvocation类型的参数,NSInvocation封装了一个方法的调用,包括方法的调用者,方法名,以及方法的参数。在forwardInvocation函数内修改方法调用对象即可。

// 方法签名:返回值类型、参数类型

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

{

    if (aSelector == @selector(driving)) {

       // return [NSMethodSignature signatureWithObjCTypes: "v@:"];

       // return [NSMethodSignature signatureWithObjCTypes: "v16@0:8"];

       // 也可以通过调用Car的methodSignatureForSelector方法得到方法签名,这种方式需要car对象有aSelector方法

        return [[[Car alloc] init] methodSignatureForSelector: aSelector];

    }

    return [super methodSignatureForSelector:aSelector];

}

//NSInvocation 封装了一个方法调用,包括:方法调用者,方法,方法的参数

//    anInvocation.target 方法调用者

//    anInvocation.selector 方法名

//    [anInvocation getArgument: NULL atIndex: 0]; 获得参数

- (void)forwardInvocation:(NSInvocation *)anInvocation

{

//  anInvocation中封装了methodSignatureForSelector函数中返回的方法。

//  此时anInvocation.target 还是person对象,我们需要修改target为可以执行方法的方法调用者。

//  anInvocation.target = [[Car alloc] init];

//  [anInvocation invoke];

    [anInvocation invokeWithTarget: [[Car alloc] init]];

}


三次握手四次挥手https://blog.csdn.net/eddyjoe/article/details/87936084

ios 用信号量控制多个异步网络请求  https://www.cnblogs.com/YuFly-lyx/p/9056378.html

设计模式  https://www.jianshu.com/p/0fb8502e9129


nstime  循环引用    https://www.jianshu.com/p/823ef4fb63bc

界面卡顿检查  https://www.jianshu.com/p/b04b72ea5e83

卡顿  检测  https://www.jianshu.com/p/15d8462718c9

catch  缓存  https://juejin.im/post/5cf3a3f46fb9a07eae2a4708

自动移除 kvo  https://www.cnblogs.com/fengmin/p/8125870.html



数据结构

https://www.cnblogs.com/xingmuxin/p/11304359.html

https://cloud.tencent.com/developer/article/1450113

LinkNode* Reverse(LinkNode* header)

{

 if (header == NULL || header->next == NULL)

 {

  return header;

 }


 LinkNode* pre = header, *cur = header->next;

 pre->next = NULL;

 while(cur != NULL)

 {

  auto next = cur-> next;

  cur->next = pre;

  pre = cur;

  cur = next;

 }

 return pre;

}

】node* reverseList(node* H)

{

    if (H == NULL || H->next == NULL) //链表为空或者仅1个数直接返回

        return H;

    node* p = H, *newH = NULL;

    while (p != NULL)                //一直迭代到链尾

    {

        node* tmp = p->next;          //暂存p下一个地址,防止变化指针指向后找不到后续的数

        p->next = newH;              //p->next指向前一个空间

        newH = p;                    //新链表的头移动到p,扩长一步链表

        p    = tmp;                  //p指向原始链表p指向的下一个空间

    }

    return newH;

}

排序https://www.runoob.com/w3cnote/sort-algorithm-summary.html

冒泡优化https://www.cnblogs.com/zsh-blogs/p/11255507.html

算法https://blog.csdn.net/bluesliuf/article/details/89043746

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