1

I have to build an application which also will be able to receive and send data. I need to create at least two threads. One to continuously listen and to respond to an interface and sending data.

var a = connectionClass()

@IBOutlet weak var textField: UITextField!
@IBAction func myButton(sender: AnyObject) {
    a.sendData()
}

override func viewDidLoad() {
    super.viewDidLoad()
    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0), { ()->() in
        print("gcd hello")
        dispatch_async(dispatch_get_main_queue(), {
            self.a.initNetworkCommunication()
            print("hello from UI thread executed as dispatch")
        })
    })
    print("hello from UI thread")
}

This code locks the user interface, however, it is receiving data. I am looking for solutions, or example, where I could see the solution to my problem.

To create stream I used code from here: https://github.com/troligtvis/SwiftChatClient/blob/master/ChatClientSwift/ViewController.swift?

=========================================================================

Ok it's working. I can open connection and send data. But now i don't know how to use function from other class to read stream. How to create self.a.stream stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) from when i don't know haw to use event and how to init NSString for aString. I know, it's stupid question but for me it is complicated.

ViewControler: import UIKit

class ViewController: UIViewController, NSStreamDelegate{

var a = connectionClass()

@IBOutlet weak var textField: UITextField!
@IBAction func myButton(sender: AnyObject) {
    a.sendData()
}
override func viewDidLoad() {
    super.viewDidLoad()
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), { ()->() in
        print("Inicjalizowanie")
        self.a.initNetworkCommunication()

        dispatch_async(dispatch_get_main_queue(), {
            print("hello from UI thread executed as dispatch")
        })
    })
    print("hello from UI thread")
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

connection class: import Foundation

class connectionClass: NSObject, NSStreamDelegate {

override init(){

}

//deklaracja podstawowych zmiennych
private let serverAddress: CFString = "someIp"
private let serverPort: UInt32 = 10001

private var inputStream: NSInputStream!
private var outputStream: NSOutputStream!
var i = 0

//Inicjalizacja połączenia
func initNetworkCommunication() {

    //zmienne potrzebne do pobierania i wysyłania danych
    var readStream: Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?

    //tworzy stream
    autoreleasepool {
    CFStreamCreatePairWithSocketToHost(nil, self.serverAddress, self.serverPort, &readStream, &writeStream)
    }
    self.inputStream = readStream!.takeRetainedValue()
    self.outputStream = writeStream!.takeRetainedValue()

    //delegaty w SWIFT - doczytać
    self.inputStream.delegate = self
    self.outputStream.delegate = self

    //tworzy pętlę dla połączenia - doczytać
    self.inputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
    self.outputStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    self.inputStream.open()
    self.outputStream.open()
    print("Zainicjalizowane")

}

//co ta funkcja robi i gdzie jest używana. Czy ona oczekuje na wywołanie połączenia z serwerem?
func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
    print("a tu jest stream")
    switch eventCode{
    case NSStreamEvent.OpenCompleted:
        print("Otwarto połączenie")
        break
    case NSStreamEvent.HasSpaceAvailable:
        if outputStream == aStream{
            print("Połączenie jest gotowe")
            break
        }
    case NSStreamEvent.HasBytesAvailable:
        print("Są ramki")
        if aStream == inputStream{
            var buffer: UInt8 = 0
            var len: Int!

            while (inputStream?.hasBytesAvailable != nil) {
                len = inputStream?.read(&buffer, maxLength: 32)
                if len > 0 {
                    let output = buffer

                    print("Server odpowiedział: \(output)")

                }
            }
        }
        break
    case NSStreamEvent.ErrorOccurred:
        print("Nie można połączyć się z serwerem!")
        break
    case NSStreamEvent.EndEncountered:
        outputStream.close()
        outputStream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
        outputStream = nil
    default:
        print("Nieznane działanie ")
    }
}

func sendData() {

    let data = NSData(bytes: [0x0F, 0x00, 0x10, 0x00, 0x00, 0x80, 0x55, 0x00, 0x55, 0x04, 0x00, 0x01, 0x00, 0x00, 0xB2, 0x04 ] as [UInt8], length: 16)

    outputStream?.write(UnsafePointer<UInt8>(data.bytes) , maxLength: data.length)

    print("wysłano: \(data)")

}

}

WujoFefer
  • 29
  • 7
  • Why not use a framework like AFNetworking or you could just not dispatch blocking network code in the main thread – Paulw11 May 12 '16 at 10:12
  • Are you getting any errors or is it just frozen? Can you provide any debug info? I am trying to figure out where you are blocking the main thread. – tacos_tacos_tacos May 12 '16 at 10:19

1 Answers1

2

First: You don't need threads to do async IO. The IO can be scheduled via GCD on the runloop. This is a good introduction: What's New in GCD.

Second: I'm not sure what you try to accomplish with your dispatch_async code section. It just runs the print in a secondary thread. Then you put your self.a.initNetworkCommunication back on the main thread ...

Third: Looking at the code from that ChatClientSwift - the a.sendData() seems to do a blocking write. Which, well, blocks ...

There are quite a few Swift GCD socket libraries available. This is one: SwiftSockets, there are more. You probably want to look at such.

hnh
  • 13,957
  • 6
  • 30
  • 40
  • I've downloaded SwiftSockets and tried to build it, but it is written in a version of Swift prior to Swift 3. And the more I tried to modify it, with and without Edit - Convert and automatic Fix-Its, the more errors I got. I'm totally new to Mac and Swift, so that's probably part of the problem. Anyway, I'd appreciate it if you could recommend some other up-to-date tutorials and/or open-source projects combining Swift 3, GCD, and TCP sockets. I'm coming up blank ... Thanks. – RenniePet Dec 07 '16 at 22:50
  • In continuation of my previous comment, I've now found this project on GitHub: https://github.com/IBM-Swift/BlueSocket It is up-to-date (Swift 3, and several commits per day at the moment) and provides a pure Swift wrapper for Sockets. It doesn't use GCD itself, but there is a test program in the "read me" that shows how GCD can be used in a calling program written in Swift. – RenniePet Dec 08 '16 at 16:58