【问题标题】:How to create and run a Thread in Swift using the Foundation framework?如何使用 Foundation 框架在 Swift 中创建和运行线程?
【发布时间】:2019-08-23 13:07:47
【问题描述】:

我想在 Swift 中创建一个简单的线程。

我以前没有使用 Objective-C 的经验,所以我发现文档相当混乱,包括“接收器”、“选择器”和“目标”等术语 - 有人可以澄清一下吗?

我目前在没有子类化 Thread 的情况下从函数启动线程的尝试如下:

https://developer.apple.com/documentation/foundation/thread

import Foundation

func run(msg: String) -> Void {
    for i in 1...1000 {
        print("\(i):\(msg)")
    }
}

let t = Thread(target: nil, selector: run, object: "helloworld")
t.start()

但是,示例无法运行,我在网上找不到任何好的示例。

有人可以提供一个解释的工作示例吗?

【问题讨论】:

  • 你应该看看 Grand Central Dispatch
  • 一些资源:Threading Programming GuideConcurrency Programming Guide。后者鼓励您使用“Grand Central Dispatch”(GCD)而不是线程。
  • Grand Central Dispatch 是执行线程的一种方式。这个是合法的。 GCD 有其自身的怪癖和局限性

标签: ios swift macos


【解决方案1】:

Thread(Objective-C 中的 NSThread)是一个相当薄的 POSIX 线程包装器。它有一些额外的管道可以与 Apple 的 Foundation 框架(在 iOS 和 Mac OS 之间很常见)进行交互。

目标和选择器的概念是 Objective-C 运行时的一部分,它是 Mac OS 上的 AppKit 和 iOS 上的 UIKit 的基础。选择器是 Objective-C 动态方法分派系统的方法签名。目标是将使用给定选择器接收方法调用的对象。

注意Thread 类也有一个初始化器,它接受一个闭包而不是一个目标/动作。如果您决定使用Threads,您可以使用该初始化程序(它会在启动时调用您的闭包。) 该初始化程序是convenience init(block: @escaping () -> Void)

正如其他人所说,出于几个原因,您最好使用 Grand Central Dispatch (GCD)。

  • 它不依赖于 Objective-C 运行时。

  • 创建和销毁线程非常昂贵,需要内核 调用,并在线程的生命周期内占用物理内存。

CGD 让系统代表您维护一个线程池。您可以使用现有的调度队列,也可以创建自己的调度队列,系统会从线程池中决定将哪些线程分配给该队列。

从 Swift 中使用它也比使用 Thread (NSThread) 类更干净。

请注意,您也可以忽略 Thread 类并直接创建 POSIX 线程,尽管我不建议这样做。

【讨论】:

  • 谢谢!我怎么能看出@escaping 意味着关闭?我不打算编写 iOS 或类似程序,而是将一些 Python 应用程序移植到 Swift 来学习这门语言。在这种情况下你还会推荐 GCD,还是应该只用于应用开发?
  • 不是@escaping 部分表明它是一个闭包(尽管这是一个闭包的限定符。)它是() -> Void 位。这是一个不带参数且不返回结果的闭包的签名。
  • GCD 通常是比线程更好的并发方式。所以是的,我建议使用 GCD。听起来您将开发 Mac 应用程序。了解 Python 和 Swift 非常不同。 Python 是一种松散类型的解释语言——一种脚本语言。 Swift 是一种适用于系统编程的编译语言。
  • 不是不断说“GCD 更好”,而是提供一些示例Thread 代码?我在 90 年代初就已经在本机线程中进行了强大的多线程处理 - 自 2005 年以来在 Java 中使用 java.util.concurrent - 我希望使用 Objective C 和/或 Swift 提供的比 dispatch 模型更接近本机的东西。
  • 我使用 NSThread(现在的 Thread)编写了相当复杂的应用程序,它是 POSIX 线程之上的一个非常薄的层。代码是用 Objective-C 编写的,而且很长,所以我不确定它的相关性。 (从那以后我切换到 GCD,所以我没有更新的基于 Thread 的代码。)如果您要使用 Thread 类中的低级线程,您需要非常了解成本创建和销毁线程,以及线程占用物理内存的事实。 GCD 使用共享线程池,因此您可以避免创建和销毁线程的开销。
【解决方案2】:

您可以使用此代码作为示例,但是正如 cmets 中提到的那样,您可以使用 Grand Central DispatchOperations 代替。它们是更现代的多线程方式。

class A {
    func start() {
        let t = Thread(target: self, selector: #selector(run(msg:)), object: "helloworld")
        t.start()
    }

    @objc func run(msg: String) {
        for i in 1...1000 {
            print("\(i):\(msg)")
        }
    }
}

let a = A()
a.start()

【讨论】:

【解决方案3】:

您应该使用 Grand Central Dispatch,但在这里:

import Foundation

let thread = Thread {
    for i in 0...100_000_000 {
        print(i)
    }
}

thread.start()

这将在后台运行,不会阻塞当前线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    • 2017-11-20
    • 2018-07-03
    相关资源
    最近更新 更多