3

I want to create a simple thread in Swift.

I've no previous experience with Objective-C, so I find the documentation pretty confusing, including terms like "receiver", "selector", and "target" - can someone clarify?

My current attempt at starting a thread from a function without subclassing Thread is as follows:

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()

However, the example will not run, and I cannot find any good examples online.

Can someone provide a working example with explanation?

Shuzheng
  • 11,288
  • 20
  • 88
  • 186
  • 3
    You should look into Grand Central Dispatch – Joakim Danielson Aug 23 '19 at 13:11
  • 2
    Some resources: The [Threading Programming Guide](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html) and the [Concurrency Programming Guide](https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/ConcurrencyandApplicationDesign/ConcurrencyandApplicationDesign.html). The latter encourages you to use “Grand Central Dispatch” (GCD) instead of threads. – Martin R Aug 23 '19 at 13:15
  • 1
    Grand Central Dispatch is _one_ way to do threading. This one is legitimate. GCD has its own quirks and limitations – WestCoastProjects May 20 '20 at 19:42

2 Answers2

4

Thread (NSThread in Objective-C) is a fairly thin wrapper around POSIX threads. It has some extra plumbing to interact with Apple's Foundation framework (which is common between iOS and Mac OS.)

The idea of targets and selectors is part of the Objective-C runtime, which is the basis of AppKit on Mac OS and UIKit for iOS. A selector is a method signature for the Objective-C dynamic method dispatch system. A target is an object that will receive a method call using a given selector.

Note that the Thread class also has an initializer that takes a closure rather than a target/action. If you're determined to use Threads you could use that initializer instead (It will call your closure when it's started.) That initializer is convenience init(block: @escaping () -> Void)

As others have said, you are better off using Grand Central Dispatch (GCD) for a couple of reasons.

  • It is not tied to the Objective-C runtime.

  • Creating and destroying threads is pretty expensive, needs a kernel call, and ties up physical memory for the lifetime of the thread.

CGD lets the system maintain a pool of threads on your behalf. You either use an existing dispatch queue or create one of your own, and the system decides which threads to assign to that queue from a pool of threads.

It is also much cleaner to use from Swift than the Thread (NSThread) class.

Note that you could also ignore the Thread class and create POSIX threads directly, although I wouldn't really recommend that.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks! How could I see that `@escaping` meant closure? I don't plan to program iOS or similar, but instead port some Python applications to Swift for learning the language. Would you still recommend GCD in that case, or should it only be used for app development? – Shuzheng Aug 24 '19 at 09:00
  • It isn't the `@escaping` part that indicates it's a closure (although that is a qualifier for a closure.) it's the `() -> Void` bit. That is the signature of a closure that takes no parameters and doesn't return a result. – Duncan C Aug 24 '19 at 20:42
  • GCD is generally a better way to do concurrency than threads. So yes, I would recommend using GCD. It sounds like you'll be developing Mac Apps. Understand that Python and Swift are very different. Python is a loosely typed interpreted language - a scripting language. Swift is a compiled language suitable for systems programming. – Duncan C Aug 24 '19 at 20:44
  • Instead of continually saying "GCD is better" is there some sample `Thread` code to provide? I did powerful multithreading in native threads in early nineties already - and in java with `java.util.concurrent` since 2005 - and want to use what Objective C and/or Swift provides closer to native than the `dispatch` model. – WestCoastProjects May 20 '20 at 19:44
  • I've written fairly complex apps using NSThread (now Thread), which is a pretty thin layer on top of POSIX threads. The code was in Objective-C, and is pretty long in the tooth, so I'm not sure how relevant it is. (since then I've switched to GCD, so I don't have more recent Thread-based code.) If you're going to use low-level threading like in the Thread class, you need to be very cognizant of the cost of creating and destroying threads, and the fact that threads tie up physical memory. GCD uses a shared thread pool, so you avoid the overhead of creating and destroying threads. – Duncan C May 20 '20 at 20:12
1

You can use this code as example, however as people mentioned in comments, you can use Grand Central Dispatch or Operations instead. They're more modern way of multithreading.

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()
Taras Chernyshenko
  • 2,729
  • 14
  • 27
  • Thanks, can you explain what a selector is, why you use `#selector`, and what the purpose of `@obj` is? – Shuzheng Aug 23 '19 at 15:17
  • @Shuzheng good answer https://stackoverflow.com/questions/24007650/selector-in-swift and here you can learn what a selector is https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html – Taras Chernyshenko Aug 23 '19 at 17:02
  • Thanks. Also, your example will not run? It says that Objective-C runtime must be present? – Shuzheng Aug 23 '19 at 17:21
  • `selector` will work only with Objective-C runtime because it is based on message dispatching – Taras Chernyshenko Aug 23 '19 at 17:35
  • 1
    It is a _different_ way to do multi-threading. Plain old threads are actually more powerful and less quirky. – WestCoastProjects May 20 '20 at 19:43