MacOS和iOS开发中异步调用与多线程的区别
很多童鞋可能对Apple开发中的异步调用和多线程的区别不是太清楚,这里本猫将用一些简单的示例来展示一下它们到底直观上有神马不同.
首先异步调用可以在同一个线程中,也可以在多个不同的线程中.每个线程都有一个run loop,主线程的运行环称为main run loop,所有和UI界面有关的操作必须在主运行环中完成.在run loop中线程将会轮询消息源发出的消息.比如在MacOS中鼠标就是一个消息源,鼠标按下就会给系统中相关线程的消息环发送消息;而在iOS中手势操作也是一个消息源,当对应的手势出现时,也会给有关线程的run loop发送消息.
run loop接收到消息源发送的消息后会发生什么呢?它会调用之前设置好的消息回调方法,比如手势操作对象会在创建时设置一个回调闭包.在手势消息送达运行环时,就会调用这个闭包.这就是异步调用的一种典型的使用方法.
异步调用不立即返回值,而是等到某个特定的时机再完成特定的调用.值得注意的是,正如前面强调过的那样,如果你在多线程中使用异步调用视图更新用户界面,你必须将实际updateUI的代码放到main run loop中执行,否则没有效果.
下面先看一下异步调用的示例代码,必须在Xcode8.0beta的playground中测试,因为是Swift 3.0的语法:
import UIKit
@objc class Time:NSObject{
@objc(one:)
func one(timer:Timer!){
print(#function)
}
@objc(two:)
func two(timer:Timer!){
print(#function)
}
}
let t = Time()
let timer1 = Timer(timeInterval: 1.0, target: t, selector: #selector(Time.one(timer:)), userInfo: nil, repeats: true)
let timer2 = Timer(timeInterval: 1.0, target: t, selector: #selector(Time.two(timer:)), userInfo: nil, repeats: true)
RunLoop.current.add(timer1, forMode: .defaultRunLoopMode)
RunLoop.current.add(timer2, forMode: .defaultRunLoopMode)
RunLoop.current.run()
大家注意最后一行,实际在graphic类型的App中这一行是不需要加的,因为UI App自身会驱动消息环使其中的任何Timer自动触发,但是在console类型的App中(比如MacOS)必须要手动run一次.
以上代码运行结果会反复打印出以下内容:
one(timer:)
two(timer:)
one(timer:)
two(timer:)
one(timer:)
two(timer:)
下面我们马上来验证异步调用默认都是在同一线程这一特性,因为在线程的run loop中所有触发和处理都是同步的,如果某一个事件的处理耗时很久或挂起了线程,则该线程中其他的操作都不会响应,即便有新的事件源被触发.
我们只需要简单的将代码中one方法修改为如下内容即可观察这一有趣的现象:
func one(timer:Timer!){
print(#function)
for _ in 0...100000000{
//Do Nothing...
}
}
运行代码片段,你可以很清楚的看到,在one方法执行完成之前two方法不可能被执行,即使前面two方法被设置为1.0秒执行一次.这是因为one方法挂起了run loop,所有其他消息源都不会被处理.
最后让本猫带大家看一下异步调用在多线程中带来的变化,我们在playground中新建一个helper方法:
func invokeTimerInNewThread(methodName:String){
let thread = Thread() {
let timer = Timer(timeInterval: 1.0, target: t, selector: NSSelectorFromString(methodName), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
RunLoop.current.run()
while true{
Thread.sleep(forTimeInterval: 1.0)
}
}
thread.start()
}
以上代码有2点要注意:
- 如果不做任何操作线程在执行完闭包方法中的代码后会很快终止,所以你必须添加一个无限循环,尽管你可以将死循环可以写的更优雅一些 ;]
- 线程对象必须用start方法启动后才会运行
哦鸟!就是这么简单,下面把原来playground中的Timer创建代码统统删除,修改为如下代码:
invokeTimerInNewThread(methodName: "one:")
invokeTimerInNewThread(methodName: "two:")
while true{
Thread.sleep(forTimeInterval: 1.0)
}
没错,playground中的主线程也必须最后添加一个无限循环,否则你看不到任何东西.运行playground,你将看到如下输出:
two(timer:)
one(timer:)
two(timer:)
two(timer:)
two(timer:)
two(timer:)
two(timer:)
这正是异步调用和多线程的一本质区别!!!one方法在循环结束前会一直挂起,之后的one方法回调将不会得到任何机会执行,原因前面说过了,one方法所在的线程被挂起了!但是这丝毫不会影响two方法的执行,因为two方法在另一个线程中啊!
MacOS和iOS开发中异步调用与多线程的区别的更多相关文章
- ios开发中如何调用苹果自带地图导航
前段时间一直在赶项目,在外包公司工作就是命苦,天天加班不说,工作都是和工期合同挂钩的,稍微逾期就有可能被扣奖金,不谈这些伤脑筋的事情了,让我们说说iOS开发中如何调用苹果手机自带的地图. 学习如逆水行 ...
- 在ios开发中nil和NUll和Nilde区别————和如何判断连个对象的关系和UISlider不能拖动的问题
nil表示一个对象指针为空,针对对象 >示例代码: NSString *someString = nil; NSURL *someURL = nil; id someObject = nil; ...
- iOS开发中常用方法调用顺序
- IOS开发中AVFoundation中AVAudioPlayer的使用
IOS开发中如何调用音频播放组件 1.与音频相关的头文件等都在AVFoundation.h中,所以第一步是添加音频库文件: #import <AVFoundation/AVFoundation. ...
- ios开发中全局变量设置和调用方法
ios开发中,全局变量设置和调用方法如下:在AppDelegate.h文件中设置全局变量:@interface ***AppDelegate{NSString *myName;}@property ( ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- 多线程在iOS开发中的应用
多线程基本概念 01 进程 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 02 线程 2-1 基本概念 1个进程要想执行任务,必须得有线程 ...
- iOS开发中文件的上传和下载功能的基本实现-备用
感谢大神分享 这篇文章主要介绍了iOS开发中文件的上传和下载功能的基本实现,并且下载方面讲到了大文件的多线程断点下载,需要的朋友可以参考下 文件的上传 说明:文件上传使用的时POST请求,通常把要上传 ...
- iOS开发中遇到的一些问题及解决方案【转载】
iOS开发中遇到的一些问题及解决方案[转载] 2015-12-29 [385][scrollView不接受点击事件,是因为事件传递失败] // // MyScrollView.m // Creat ...
随机推荐
- AutoFac+MVC+WebApi源码----我踩过的坑
发现网上关于AutoFac的Demo源码比较少,综合MVC和WepApi的更少.所以贴出源码 WebApi项目(MVC4不需要引用,历史遗留问题,人懒没删) 建项目 新建类库IAutoFacDal(接 ...
- PostgreSQL 常用系统自带方法
数据库字符编码问题: -- 查看PostgreSQL数据库服务器端编码: show server_encoding; -- 查看PostgreSQL客户端工具psql编码: s ...
- 一、spring的成长之路——代理设计模式
java常用的设计模式详解: 1.代理模式(JDK的动态代理) [IDept.java] 这是一个简单的就接口,进行数据的更新 package com.itcloud.pattern.proxy; ...
- [LeetCode] Set Intersection Size At Least Two 设置交集大小至少为2
An integer interval [a, b] (for integers a < b) is a set of all consecutive integers from a to b, ...
- QueryRunner--常见方法
数据库链接池的使用,一方面解决了数据库访问过多时造成数据库承受的压力,另一方面也简化了数据查询,今天就 DBUtils包所提供的QueryRunner类(org.apache.commons.dbut ...
- EventBus InMemory 的实践基于eShopOnContainers (二)
前言 最近在工作中遇到了一个需求,会用到EventBus,正好看到eShopOnContainers上有相关的实例,去研究了研究.下面来分享一下用EventBus 来改造一下我们上篇Event发布与实 ...
- [测试题]gene
Description Input Output Sample Input 3A+00A+A+ 00B+D+A- B-C+00C+ Sample Output bounded Hint 题解 //It ...
- ●BZOJ 2555 SubString
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2555题解: 后缀自动机+LCT 不难发现,对于输入的询问串,在自动机里trans后的到的状态 ...
- 洛谷P3168 [CQOI2015]任务查询系统
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...
- poj 2960 S-Nim
S-Nim Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4113 Accepted: 2158 Description ...