iosLearner
iosLearner

Reputation: 1331

NSOutputStream blocking, HasBytesAvailable event was not triggered

I am trying to create custom framework that will deal with ExternalAccessory.framework to do read/write operation with the connected accessory.

I can able to create a session and open the device to do read/write operations. Problem i am facing was, when i try to write data using NSOutputStream.write from the application, data successfully received by the accessory but after that UI was not responding and data returned byte accessory was not received by the app(HasBytesAvailable was not called)

Here my UIViewController.swift

let sessionHandler = SessionHandler().sharedController()

in ViewDidLoad()

let runLoop = NSRunLoop.currentRunLoop()
sessionHandler.openDeviceWithProtocolString(runLoop)

@IBAction calling sessionHandler._WriteData()

This SessionHandler class was in inside my custom SDK (custom framework)

Here my SessionHandler Class

import UIKit
import ExternalAccessory


public class SessionHandler: NSObject, NSStreamDelegate {

    var readData: NSMutableData?
    var writeData: NSMutableData?
    var _session: EASession?

    public func sharedController() -> SessionHandler{
        var sessionController: SessionHandler?
        if sessionController == nil {
            sessionController = SessionHandler()
        }
        return sessionController!
    }

    func getConnectedAccessoris() -> Array<EAAccessory>{
        let accessories : Array<EAAccessory> = EAAccessoryManager.sharedAccessoryManager().connectedAccessories
        return accessories
    }


    public func openDeviceWithProtocolString(_runLoop: NSRunLoop){
        print("Inside openDeviceWithProtocolString")
        let _accessories = getConnectedAccessoris()
        var _accessory: EAAccessory?
        for acsy in _accessories {
            if acsy.protocolStrings.contains("my.protocol.string") {
                _accessory = acsy
            }
        }
        if _accessory != nil {
            _session = EASession(accessory: _accessory!, forProtocol: "my.protocol.string")
            print("EASession create :: \(_session)")
            if _session != nil {

                _session?.inputStream?.delegate = self
                _session?.inputStream?.scheduleInRunLoop(_runLoop, forMode: NSDefaultRunLoopMode)
                _session?.inputStream?.open()
                print("Input stream Opened")
                _session?.outputStream?.delegate = self
                _session?.outputStream?.scheduleInRunLoop(_runLoop, forMode: NSDefaultRunLoopMode)
                _session?.outputStream?.open()
                print("Output Stream Opened")
            }else {
                print("SessionHandler : session nil")
            }
        }
    }



    public func _readData() {
        print("Trying to read data")
        let INPUT_BUFFER_SIZE = 65536
        let buf = UnsafeMutablePointer<UInt8>.alloc(INPUT_BUFFER_SIZE)
        while ((_session?.inputStream?.hasBytesAvailable) != nil) {
            let bytesRead = _session?.inputStream?.read(buf, maxLength: INPUT_BUFFER_SIZE)
            if readData == nil {
                readData = NSMutableData()
            }
            readData?.appendBytes(buf, length: bytesRead!)
        }
        if readData != nil {
            let data: NSData = readData!
            let count = data.length / sizeof(UInt8)

            // create an array of Uint8
            var array = [UInt8](count: count, repeatedValue: 0)

            // copy bytes into array
            data.getBytes(&array, length:count * sizeof(UInt8))
            print("Data Received :: \(array)")
            validateData(array)
        }
    }

    public func _writeData() {

        while _session?.outputStream?.hasSpaceAvailable != nil && writeData?.length > 0 {
            print("Writting bytes :: \(writeData?.bytes)")
            let bytesWritten = _session?.outputStream?.write(UnsafePointer<UInt8>((writeData?.bytes)!), maxLength: (writeData?.length)!)
            print("written bytes : \(bytesWritten)")
            if bytesWritten == -1 {
                //Write error
                print("written error")
                break
            }else if bytesWritten > 0 {
                print("Written success")
                validateData(writeData)
                writeData?.replaceBytesInRange(NSMakeRange(0, bytesWritten!), withBytes: nil, length: 0)
            }
        }
    }


    func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
        switch (eventCode) {
        case NSStreamEvent.None:
            print("NSStream None")
            break
        case NSStreamEvent.OpenCompleted:
            print("Open Completed")
            break
        case NSStreamEvent.HasBytesAvailable:
            print("Has Bytes Available")
            _readData()
            break
        case NSStreamEvent.HasSpaceAvailable:
            print("Hase space Available")
            _writeData()
            break
        case NSStreamEvent.ErrorOccurred:
            print("Error occurred")
            break
        case NSStreamEvent.EndEncountered:
            print("End Encountered")
            break
        default:
            print("No stream event")
            break
        }
    }
}

Thanks in Advance..

Upvotes: 2

Views: 1071

Answers (2)

Chris J
Chris J

Reputation: 121

I'm sure this is too late, but

while ((_session?.inputStream?.hasBytesAvailable) != nil)
looks like an infinite loop to me, because true/false will always be != nil.

Upvotes: 0

SwiftGod
SwiftGod

Reputation: 386

sessionHandler.openDeviceWithProtocolString(runLoop)

Isn't it supposed to be called on another thread?

Upvotes: 0

Related Questions