共计 7744 个字符,预计需要花费 20 分钟才能阅读完成。
GCD 怎么用的?
本文收录:https://juejin.cn/post/6976878024566243335
1.串行队列,同步操作 ,不会新建线程,操作程序执行;
串行队列,异步操作,会新建线程,操作程序进行,
应用场景: 既不影响主线程,又须要程序执行的操作;
2.并行队列,同步操作,不会新建县城,操作程序执行;
并行队列,异步操作,会新建线程,操作无序进行,队列前如果有其余工作,会期待其余工作执行结束再执行;
全局队列 是零碎的,间接 get 就能够用
UI 的更新工作必须在主线程进行,
全局队列异步操作,会新建对个子线程,操作无序执行,如果队列前有其余工作,会期待其余工作执行结束在调用;
全局队列同步操作 ,不会新建线程,程序执行
队列所有的操作都是主线程程序执行,没有异步概念,主队列增加的同步操作永远不会执行,会死锁
单例模式
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 = -lxml2
HEADER_SEARCH_PATHS = /usr/include/libxml2
libidn
全局队列与并行队列的区别
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