很多童鞋可能对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点要注意:

  1. 如果不做任何操作线程在执行完闭包方法中的代码后会很快终止,所以你必须添加一个无限循环,尽管你可以将死循环可以写的更优雅一些 ;]
  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开发中异步调用与多线程的区别的更多相关文章

  1. ios开发中如何调用苹果自带地图导航

    前段时间一直在赶项目,在外包公司工作就是命苦,天天加班不说,工作都是和工期合同挂钩的,稍微逾期就有可能被扣奖金,不谈这些伤脑筋的事情了,让我们说说iOS开发中如何调用苹果手机自带的地图. 学习如逆水行 ...

  2. 在ios开发中nil和NUll和Nilde区别————和如何判断连个对象的关系和UISlider不能拖动的问题

    nil表示一个对象指针为空,针对对象 >示例代码: NSString *someString = nil; NSURL *someURL = nil; id someObject = nil; ...

  3. iOS开发中常用方法调用顺序

  4. IOS开发中AVFoundation中AVAudioPlayer的使用

    IOS开发中如何调用音频播放组件 1.与音频相关的头文件等都在AVFoundation.h中,所以第一步是添加音频库文件: #import <AVFoundation/AVFoundation. ...

  5. ios开发中全局变量设置和调用方法

    ios开发中,全局变量设置和调用方法如下:在AppDelegate.h文件中设置全局变量:@interface ***AppDelegate{NSString *myName;}@property ( ...

  6. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  7. 多线程在iOS开发中的应用

    多线程基本概念 01 进程 进程是指在系统中正在运行的一个应用程序.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 02 线程 2-1 基本概念 1个进程要想执行任务,必须得有线程 ...

  8. iOS开发中文件的上传和下载功能的基本实现-备用

    感谢大神分享 这篇文章主要介绍了iOS开发中文件的上传和下载功能的基本实现,并且下载方面讲到了大文件的多线程断点下载,需要的朋友可以参考下 文件的上传 说明:文件上传使用的时POST请求,通常把要上传 ...

  9. iOS开发中遇到的一些问题及解决方案【转载】

    iOS开发中遇到的一些问题及解决方案[转载] 2015-12-29 [385][scrollView不接受点击事件,是因为事件传递失败] // //  MyScrollView.m //  Creat ...

随机推荐

  1. Linux64位程序中的漏洞利用

    之前在栈溢出漏洞的利用和缓解中介绍了栈溢出漏洞和一些常见的漏洞缓解 技术的原理和绕过方法, 不过当时主要针对32位程序(ELF32). 秉承着能用就不改的态度, IPv4还依然是互联网的主导, 更何况 ...

  2. 连接mysql数据库报错java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized...解决方法

    今天连接mysql数据库报错如下: java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or r ...

  3. 初学Servlet之继承GenericServlet

    package app01a;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.GenericSer ...

  4. preg_replace引发的phpmyadmin(4.3.0-4.6.2)命令执行漏洞

    编辑器坏了 (:  今天看到这个phpmyadmin的代码执行,https://www.waitalone.cn/phpmyadmin-preg_replace-rce.html 记录一下:preg_ ...

  5. [NOI 2010]航空管制

    Description 世博期间,上海的航空客运量大大超过了平时,随之而来的航空管制也频频发生.最近,小X就因为航空管制,连续两次在机场被延误超过了两小时.对此,小X表示很不满意. 在这次来烟台的路上 ...

  6. [PA 2014]Kuglarz

    Description 魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品.花费c_ij元,魔术师就会告诉你杯子i,i+ ...

  7. ●BZOJ 2049 [Sdoi2008]Cave洞穴勘测

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2049 题解: LCT入门题 就是判两个点是否在同一颗树里 代码: #include<c ...

  8. 例10-4 uva10791(唯一分解)

    题意:求最小公倍数为n的数的和的最小值. 如12:(3,4),(2,6),(1,12)最小为7 要想a1,a2,a3……an的和最小,要保证他们两两互质,只要存在不互质的两个数,就一定可以近一步优化 ...

  9. bzoj1877

    1877: [SDOI2009]晨跑 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 2660  Solved: 1424[Submit][Status][ ...

  10. (MariaDB)开窗函数用法

    本文目录: 1.1 窗口和开窗函数简介 1.2 OVER()语法和执行位置 1.3 row_number()对分区排名 1.4 rank()和dense_rank() 1.5 percent_rank ...