Search code examples
iosbluetoothcore-bluetoothnsstreaml2cap

Proper way to setup NSStreams?


I'm writing a little peer-to-peer bluetooth chat app. What I'm currently doing is:

let thread = Thread(block: { [weak self] in
    guard let `self` = self else { return }

    self.channel.inputStream.delegate = self
    self.channel.inputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
    self.channel.inputStream.open()

    self.channel.outputStream.delegate = self
    self.channel.outputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
    self.channel.outputStream.open()

    RunLoop.current.run()
})

thread.start()

Where self.channel is CBL2CAPChannel The problem I'm currently facing is that it generates new thread for each pair of channels and eventually there are too many threads hanging around.

What is proper way to set up CBL2CAPChannels in this case? Apple's docs are using main thread for this, which is unexpected and could lead to problems when there are a lot of connections.


Solution

  • Apple's docs are using main thread for this, which is unexpected and could lead to problems when there are a lot of connections.

    It isn't unexpected; it's totally normal. You shouldn't be creating separate threads for every stream. The whole point of run loops is to handle concurrency without creating new threads. In run loop programming, you very rarely create new threads. Run loop programming comes from long before multi-core systems and was designed for cooperative multitasking (rather than preemptive multitasking).

    Even if you wanted to put things off onto other cores, you should never create a Thread object unless you're interacting with C++ code that requires it. There haven't been many good reasons to use NSThread directly for almost a decade. You pass the work to GCD using DispatchQueue. Passing the data from the stream to another dispatch queue for processing is a very normal approach, and gets almost all the work off of the main queue (the main queue then just does coordination).

    If you have a large number of connections, or they are very busy, then you might consider putting all of them onto a separate thread (not one thread per connection; one thread total). But it's unlikely that at L2CAP rates you'd need to do that. I built Mac chat apps for G4s less powerful than an iPhone 5 with a single thread.