写点什么

iOS 面试残篇 - 辟邪剑谱

用户头像
关注
发布于: 11 小时前
iOS面试残篇-辟邪剑谱

GCD 怎么用的?

1.串行队列,同步操作,不会新建线程,操作顺序执行;串行队列,异步操作,会新建线程,操作顺序进行,使用场景: 既不影响主线程,又需要顺序执行的操作;


2.并行队列,同步操作,不会新建县城,操作顺序执行;并行队列,异步操作,会新建线程,操作无序进行,队列前如果有其他任务,会等待其他任务执行完毕再执行;


全局队列是系统的,直接 get 就可以用 UI 的更新工作必须在主线程进行,


全局队列异步操作,会新建对个子线程,操作无序执行,如果队列前有其他任务,会等待其他任务执行完毕在调用;


全局队列同步操作,不会新建线程,顺序执行队列所有的操作都是主线程顺序执行,没有异步概念,主队列添加的同步操作永远不会执行,会死锁


本文收录:https://juejin.cn/post/6976878024566243335

单例模式

allocwithzone 是对象分配内存空间时,最终会调用的方法,重写该方法,保证只会分配一块内存 dispatch_once 是线程安全的,保证块代码中的内容只会执行一次


串行队列添加的同步操作会死锁,但是会执行嵌套同步操作之前的代码;


并行队列添加的同步操作不会死锁都在主线程执行;


全局队列添加的同步操作不会死锁。


同步操作 最主要的目的,阻塞并行队列任务的执行,只有当前的同步任务执行完毕之后,后边的任务才会执行,应用: 用户登录

队列和线程的区别:

队列: 是管理线程的,相当于线程池,能管理线程什么时候执行。

队列分为串行队列和并行队列

串行队列: 队列中的线程按顺序执行(不会同时执行)


并行队列: 队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列,也就是说你即使执行完毕了,也必须等前面的任务执行完毕出队列,才可以出去。

主线程队列和 GCD 创建的队列也是有区别的。

主线程队列和 GCD 创建的队列是不同的。

在 GCD 中创建的队列优先级没有主队列高,所以在 GCD 中的串行队列开启同步任务里面没有嵌套任务是不会阻塞主线程,只有一种可能导致死锁,就是串行队列里,嵌套开启任务,有可能会导致死锁。

主线程队列中不能开启同步,会阻塞主线程。

只能开启异步任务,开启异步任务也不会开启新的线程,只是降低异步任务的优先级,让 cpu 空闲的时候才去调用。而同步任务,会抢占主线程的资源,会造成死锁。

线程:里面有非常多的任务(同步,异步)

同步与异步的区别:

同步任务优先级高,在线程中有执行顺序,不会开启新的线程。


异步任务优先级低,在线程中执行没有顺序,看 cpu 闲不闲。


在主队列中不会开启新的线程,其他队列会开启新的线程。


主线程队列注意:


  • 下面代码执行顺序

  • 1111

  • 2222

主队列异步

<NSThread: 0x8e12690>{name = (null), num = 1}
复制代码

在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为什么不会阻塞线程?

主队列开启异步任务,虽然不会开启新的线程,但是他会把异步任务降低优先级,等闲着的时候,就会在主线程上执行异步任务。

在主队列开启同步任务,为什么会阻塞线程?

在主队列开启同步任务,因为主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,因为他是无限循环的,除非关闭应用程序。因此在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操作,不肯放手。两个的优先级都很高,最终导致死锁,阻塞线程了。


- (void)main_queue_deadlock{
dispatch_queue_t q = dispatch_get_main_queue(); NSLog(@"1111"); dispatch_async(q, ^{ NSLog(@"主队列异步 %@", [NSThread currentThread]); }); NSLog(@"2222"); // 下面会造成线程死锁 // dispatch_sync(q, ^{ // NSLog(@"主队列同步 %@", [NSThread currentThread]); // });
}
复制代码
并行队列里开启同步任务是有执行顺序的,只有异步才没有顺序;
串行队列开启异步任务,是有顺序的
串行队列开启异步任务后嵌套同步任务造成死锁
  - (void)serial_queue_deadlock2    {        dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);                        dispatch_async(q, ^{            NSLog(@"异步任务 %@", [NSThread currentThread]);            // 下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的异步任务执行完毕,才会执行下面开启的同步任务。而上面的异步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。            dispatch_sync(q, ^{                NSLog(@"同步任务 %@", [NSThread currentThread]);            });            });
复制代码
串行队列开启同步任务后嵌套同步任务造成死锁
- (void)serial_queue_deadlock1    {        dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);                dispatch_sync(q, ^{            NSLog(@"同步任务 %@", [NSThread currentThread]);            // 下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的同步任务执行完毕,才会执行下面开启的同步任务。而上面的同步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。            dispatch_sync(q, ^{                NSLog(@"同步任务 %@", [NSThread currentThread]);            });                    });        NSLog(@"同步任务 %@", [NSThread currentThread]);    }    串行队列开启同步任务后嵌套异步任务不造成死锁
复制代码

网络:

PUT 方法

PUT

  1. 文件大小无限制

  2. 可以覆盖文件

POST

  1. 通常有限制 2M

  2. 新建文件,不能重名


BASE 64 是网络传输中最常用的编码格式 - 用来将二进制的数据编码成字符串的编码方式

BASE 64 的用法:

1> 能够编码,能够解码 2> 被很多的加密算法作为基础算法

音频处理

依赖的框架:AVFoundation、AudioToolbox 框架

播放长音乐:AVAudioPlayer

播放短音效:加载音频文件生成 SystemSoundID

录音:AVAudioRecord

较为底层、高级的音频\视频处理

CoreAudio、CoreVideo 框架

XMPP 工作原理

节点连接到服务器

服务器利用本地目录系统中的证书对其认证

节点指定目标地址,让服务器告知目标状态

服务器查找、连接并进行相互认证

节点之间进行交互

XMPP 框架提供的主要扩展功能

XMPPReconnect:如果意外中断,自动重连 XMPP 流

XMPPRoster:标准的 XMPP 花名册

XMPPRoom:提供多人聊天支持

XMPPPubSub:提供公共订阅支持

通信类别及公共 XML 属性

使用 XMPP 的实时消息传递系统包含三大通信类别:

消息传递,其中数据在有关各方之间传输

联机状态,允许用户广播其在线状态和可用性

信息/查询请求,它允许 XMPP 实体发起请求并从另一个实体接收响应

以上三种类型的 XMPP 节都拥有以下公共属性:

from:源 XMPP 实体的 JID

to:目标接收者的 JID

id:当前对话的可选标识符

type:节的可选子类型

xml:lang:如果内容是人们可读的,则为消息语言的描述

XMPP 核心文件

XMPPStream:是开发过程中最主要交互的类,所有扩展和自定义代码均要基于此类进行

XMPPParser:供 XMPPStream 解析使用

XMPPJID:提供了一个不可变 JID 的实现,遵守 NSCopying 协议和 NSCoding 协议

XMPPElement:以下三个 XMPP 元素的基类

XMPPIQ:请求

XMPPMessage:消息

XMPPPresence:出席

XMPPModule:开发 XMPP 扩展时使用

XMPPLogging:XMPP 的日志框架

XMPPInternal:整个 XMPP 框架内部使用的核心和高级底层内容

XMPP 框架常用扩展

XEP-0045: 多用户聊天

XEP-0060: 发布-订阅

XEP-0065: SOCKS5 字节流

XEP-0085: 聊天状态通知

XEP-0096: 文件传输

XEP-0172: 用户昵称

XEP-0184: 消息送达

CoreDataStorage: 数据存储

Reconnect:重新连接

Roster:花名册

XMPP 一栏的框架

CocoaLumberjack:日志框架

CocoaAsyncSocket:底层网络框架,实现异步 Socket 网络通讯


需要添加 CFNetwork&Security 框架依赖


KissXML:XML 解析框架


需要添加 libxml2.dylib 框架依赖

需要指定如下编译选项:
OTHER_LDFLAGS = -lxml2HEADER_SEARCH_PATHS = /usr/include/libxml2libidn
复制代码

全局队列与并行队列的区别

dispatch_queue_t q =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
复制代码


1> 不需要创建,直接 GET 就能用

2> 两个队列的执行效果相同

3> 全局队列没有名称,调试时,无法确认准确队列

4> 全局队列有高中默认优先级

并行队列

dispatch_queue_t q = dispatch_queue_create("ftxbird", DISPATCH_QUEUE_CONCURRENT);

串行队列

dispatch_queue_t t = dispatch_queue_create("ftxbird",DISPATCH_QUEUE_SERIAL);

开发中,跟踪当前线程

[NSThread currentThread]

并行队列的任务嵌套例子

   dispatch_queue_t q = dispatch_queue_create("ftxbird", DISPATCH_QUEUE_CONCURRENT);       // 任务嵌套        dispatch_sync(q, ^{          NSLog(@"1 %@", [NSThread currentThread]);                       dispatch_sync(q, ^{                NSLog(@"2 %@", [NSThread currentThread]);                               dispatch_sync(q, ^{
NSLog(@"3 %@", [NSThread currentThread]); }); }); dispatch_async(q, ^{
NSLog(@"4 %@", [NSThread currentThread]); });
NSLog(@"5 %@", [NSThread currentThread]);
});
复制代码

主队列(线程)

1>每一个应用程序都只有一个主线程

2>所有 UI 的更新工作,都必须在主线程上执行!

3>主线程是一直工作的,而且除非将程序杀掉,否则主线程的工作永远不会结束!dispatch_queue_t q = dispatch_get_main_queue();

在主队列上更新 UI 的例子

    //创建代码块    void (^TaskOne)(void) = ^(void)    {        NSLog(@"Current thread = %@", [NSThread currentThread]);        NSLog(@"Main thread = %@", [NSThread mainThread]);               [[[UIAlertView alloc] initWithTitle:@"GCD"                                    message:@"Great Center Dispatcher"                                   delegate:nil                          cancelButtonTitle:@"OK"                          otherButtonTitles:nil, nil] show];    };       //取得分发队列    dispatch_queue_t mainQueue = dispatch_get_main_queue();       //提交任务    dispatch_async(mainQueue, TaskOne);}    //简便写法   dispatch_async( dispatch_get_main_queue(), ^(void)    {             NSLog(@"Current thread = %@", [NSThread currentThread]);       NSLog(@"Main thread = %@", [NSThread mainThread]);             [[[UIAlertView alloc] initWithTitle:@"GCD"                                   message:@"Great Center Dispatcher"                                  delegate:nil                         cancelButtonTitle:@"OK"                         otherButtonTitles:nil, nil] show];    });
复制代码

NSOperation 多线程技术

NSBlockOperation 简单使用

//开发中一般给自定义队列定义为属性@property (nonatomic, strong) NSOperationQueue *myQueue;self.myQueue = [[NSOperationQueue alloc] init];
复制代码


1>在自定义队列


NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"%@", [NSThread currentThread]);}];


所有的自定义队列,都是在子线程中运行.


[self.myQueue addOperation:block];


或者:


[self.myQueue addOperationWithBlock:^{NSLog(@"%@", [NSThread currentThread]);}];


2>在主队列中执行


[[NSOperationQueue mainQueue] addOperationWithBlock:^{NSLog(@"%@", [NSThread currentThread]);}];

NSInvocationOperation 简单使用

 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demoOp:) object:@"hello op"];
- (void)demoOp:(id)obj{ NSLog(@"%@ - %@", [NSThread currentThread], obj);}
复制代码

performSelectorOnMainThread 方法使用

        // 1> 模拟下载,延时        [NSThread sleepForTimeInterval:1.0];
// 2> 设置图像,苹果底层允许使用performSelectorInBackground方法 // 在后台线程更新UI,强烈不建议大家这么做! // YES会阻塞住线程,直到调用方法完成 // NO不会阻塞线程,会继续执行 [self performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageNamed:imagePath] waitUntilDone:NO];
// 1. 图像 - (void)setImage:(UIImage *)image { self.imageView.image = image; [self.imageView sizeToFit]; }
复制代码

提问:代码存在什么问题?如果循环次数非常大,会出现什么问题?应该如何修改?

 // 解决办法1:如果i比较大,可以在for循环之后@autoreleasepool // 解决方法2:如果i玩命大,一次循环都会造成          自动释放池被填满,一次循环就@autoreleasepool    for (int i = 0; i < 10000000; ++i) {        @autoreleasepool {            // *            NSString *str = @"Hello World!";            // new *            str = [str uppercaseString];            // new *            str = [NSString stringWithFormat:@"%@ %d", str, i];                       NSLog(@"%@", str);        }    }
复制代码

文末推荐:iOS 热门文集 &视频解析

① Swift

② iOS底层技术

③ iOS逆向防护

④ iOS面试合集

⑤ 大厂面试题+底层技术+逆向安防+Swift

用户头像

关注

你的努力没人会看到,可成功会让人羡慕。 2020.12.08 加入

iOS交流群:642363427 公众号:iOS进阶宝典 抖音:iOS 普拉斯 视频学习:https://space.bilibili.com/107521719 感谢支持与关注

评论

发布
暂无评论
iOS面试残篇-辟邪剑谱