Skip to content

Instantly share code, notes, and snippets.

@lucasecf
Last active February 24, 2023 23:16
Show Gist options
  • Save lucasecf/bde1d9bd3492f29b7534 to your computer and use it in GitHub Desktop.
Save lucasecf/bde1d9bd3492f29b7534 to your computer and use it in GitHub Desktop.
Example of how to use the streaming feature of the iOS MultipeerConnectivity framework
/*
For this Gist, we have two sides: sender and receiver. The same user can be a sender and a receiver, but I will separate this
two roles to be more clear.
This gist assumes thatyou already have a MCSession created, and the peers are connected,
*/
//First, we are in the sender side. We need to have a NSOutputStream property, in order to send data to the receiver.
var outputStream:NSOutputStream?
//Somewhere, schedule the stream in the mainRunLoop, set the delegate and open it. Choose the peer that you want to connect.
var err:NSError? = nil
outputStream = session.startStreamWithName("chat", toPeer: session.connectedPeers.first as MCPeerID, error:&err)
if let outputStream = outputStream {
outputStream.delegate = self
outputStream.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode:NSDefaultRunLoopMode)
outputStream.open()
}
/*
On the receiver side, the application will call the MCSessionDelegate. Receive the stream, schedule in the mainRunLoop too and open it.
Optionally check if the received stream is the one you want with the streamName parameter
*/
func session(session: MCSession!, didReceiveStream stream: NSInputStream!, withName streamName: String!, fromPeer peerID: MCPeerID!) {
stream.delegate = self
stream.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)
stream.open()
}
//After the two streams are opened, on the sender side, you can write the data with the code below:
let message = "This is a string test"
let data = NSKeyedArchiver.archivedDataWithRootObject(message) //this is a NSData instance. Could be any NSData, as a serialized object, for example.
//write in the output stream the bytes array of the NSData
if let output = output {
output.write(UnsafePointer(data.bytes), maxLength: data.length)
}
//Now, again on the receiver side, you need to implement the NSStreamDelegate delegate, and the method below. This method will be called when the output writes any data to the input
func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
switch(eventCode){
case NSStreamEvent.HasBytesAvailable:
let input = aStream as NSInputStream
var buffer = [UInt8](count: 1024, repeatedValue: 0) //allocate a buffer. The size of the buffer will depended on the size of the data you are sending.
let numberBytes = input.read(&buffer, maxLength:1024)
let dataString = NSData(bytes: &buffer, length: numberBytes)
let message = NSKeyedUnarchiver.unarchiveObjectWithData(dataString) as String //deserializing the NSData
//input
case NSStreamEvent.HasSpaceAvailable:
break
//output
default:
break
}
}
//Now message will hold the sent "This is a string test"!
@mikaelho
Copy link

Thanks, exactly the example I needed!

Copy link

ghost commented Nov 4, 2018

That helped me too but things changed.
In Swift 4 it is got to be changed like this.

   _var outputStream:OutputStream?
    
    do {
     try outputStream = localSession?.startStream(withName: "test", toPeer: connectedPeers[0])
        
        
        if let outputStream = outputStream {
            outputStream.delegate = self as? StreamDelegate
            outputStream.schedule(in: RunLoop.main, forMode:RunLoopMode.defaultRunLoopMode)
            outputStream.open()
        }

     
        let string = "Testing stream"
        let data = string.data(using: String.Encoding.utf8)!
        let bytesWritten = data.withUnsafeBytes { outputStream?.write($0, maxLength: data.count) }
       
        print("buttonTakeIt bytesWritten \(String(describing: bytesWritten))")
        
    }  catch let error as NSError {
        print(" error in beginSession() = \(error)")
    }

func stream(aStream: Stream, handleEvent eventCode: Stream.Event) {
    
    switch(eventCode){
    case Stream.Event.hasBytesAvailable:
        let input = aStream as! InputStream
        var buffer = [UInt8](repeating: 0, count: 1024) //allocate a buffer. The size of the buffer will depended on the size of the data you are sending.
        let numberBytes = input.read(&buffer, maxLength:1024)
        let dataString = NSData(bytes: &buffer, length: numberBytes)
        let message = NSKeyedUnarchiver.unarchiveObject(with: dataString as Data) as! String //deserializing the NSData
        
        print("received message as stream\(message)")
    //input
    case Stream.Event.hasSpaceAvailable:
        break
    //output
    default:
        break
    }
}

_

@Yang-Xijie
Copy link

The full example using both Data and Stream. (Swift 5, Xcode 13, iOS 15)

https://github.com/Yang-Xijie/ExPeerMessage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment