I'm a socket project in swift. I try to give data that are JSON and Parse them but i have two problem:
1- when I received data are incomplete and return nil value for some bytes.
2- I don't know when The receiving data ends. I receive data in NSSTreamEvent.hasBytesAvailable but never run the NSStreamEvent.EndEncountered and after some moments the code was error and app crashed.
3- My socket 2 times open while I call them 1 time...
There is my code :
import Foundation
class SocketManager : NSObject , NSStreamDelegate {
let ip = "192.168.1.12"
let port = 6969
let introduceStr = ["Type" : 4 , "MobileID" : 2 , "Introduce" : ["ExKey" : 123]]
let jsonParser = JsonMaker() // This is a class for convert string to json
var inputStream : NSInputStream?
var outputStream : NSOutputStream?
var openedSocket = Int()
var total = NSString()
override init() {
openedSocket = 0
}
func openSocket() {
NSStream.getStreamsToHostWithName(ip, port: port, inputStream: &inputStream, outputStream: &outputStream)
let inputStatus : NSStreamStatus = (inputStream?.streamStatus)!
let outputStatus : NSStreamStatus = (outputStream?.streamStatus)!
if inputStatus != NSStreamStatus.Reading && inputStatus != NSStreamStatus.Open && inputStatus != NSStreamStatus.Opening && outputStatus != NSStreamStatus.Writing && outputStatus != NSStreamStatus.Open && outputStatus != NSStreamStatus.Opening {
inputStream?.delegate = self
outputStream?.delegate = self
inputStream?.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream?.open()
outputStream?.open()
}
}
func tryOpen() {
inputStream?.close()
outputStream?.close()
inputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
performSelector("openSocket", withObject: nil, afterDelay: 5)
}
func closeSocket() {
inputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream?.removeFromRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream?.close()
outputStream?.close()
performSelector("openSocket", withObject: nil, afterDelay: 15)
}
func getData(aStream : NSStream) {
if (aStream == inputStream) {
let MAXSIZE = 1024 * 8
var allLength = Int()
var buffer = [UInt8](count: MAXSIZE , repeatedValue: 0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
while self.inputStream?.hasBytesAvailable == true {
let readBytes = self.inputStream?.read(&buffer, maxLength: sizeofValue(buffer))
allLength += readBytes!
if readBytes > 0 {
let data : NSData = NSData(bytes: &buffer, length: sizeofValue(buffer))
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.total = (self.total as String) + (str as String)
})
}
}
}
})
}
}
func sendData(message : NSString ) -> Int{
if openedSocket == 0 {
return -1
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let data : NSData = message.dataUsingEncoding(NSUTF8StringEncoding)!
var buffer = [UInt8](count: (data.length), repeatedValue: 0)
data.getBytes(&buffer, length: buffer.count)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.outputStream!.write(&buffer, maxLength: (data.length))
})
})
return 1
}
}
func introduce() {
if openedSocket == 1{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let str = self.jsonParser.dictionaryToJson(self.introduceStr)
let data : NSData = str.dataUsingEncoding(NSUTF8StringEncoding)!
var buffer = [UInt8](count: (data.length), repeatedValue: 0)
data.getBytes(&buffer, length: buffer.count)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.outputStream!.write(&buffer, maxLength: (data.length))
print("the output introducing is finised")
})
})
} else {
tryOpen()
}
}
func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
switch eventCode {
case NSStreamEvent.ErrorOccurred :
print("This is the Errorrr")
break
case NSStreamEvent.OpenCompleted :
openedSocket = 1
performSelector("introduce", withObject: nil, afterDelay: 0.3)
break
case NSStreamEvent.HasBytesAvailable :
getData(aStream)
break
case NSStreamEvent.EndEncountered :
print(total)
break
default :
break
}
}
}
Related
I want to check if device is having very slow internet connection.
I have used Reachability class to check for internet connection is available or not.
But here i want to check after every few sec that internet speed is not poor.
Is this possible to find and yes than how can i do it.
I have founded solution and adding it here.
Simply create class and paste it and use it where you want.
protocol NetworkSpeedProviderDelegate: class {
func callWhileSpeedChange(networkStatus: NetworkStatus)
}
public enum NetworkStatus :String
{case poor; case good; case disConnected}
class NetworkSpeedTest: UIViewController {
weak var delegate: NetworkSpeedProviderDelegate?
var startTime = CFAbsoluteTime()
var stopTime = CFAbsoluteTime()
var bytesReceived: CGFloat = 0
var testURL:String?
var speedTestCompletionHandler: ((_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void)? = nil
var timerForSpeedTest:Timer?
func networkSpeedTestStart(UrlForTestSpeed:String!){
testURL = UrlForTestSpeed
timerForSpeedTest = Timer.scheduledTimer(timeInterval: 60.0, target: self, selector: #selector(testForSpeed), userInfo: nil, repeats: true)
}
func networkSpeedTestStop(){
timerForSpeedTest?.invalidate()
}
#objc func testForSpeed()
{
testDownloadSpeed(withTimout: 2.0, completionHandler: {(_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void in
print("%0.1f; KbPerSec = \(megabytesPerSecond)")
if (error as NSError?)?.code == -1009
{
self.delegate?.callWhileSpeedChange(networkStatus: .disConnected)
}
else if megabytesPerSecond == -1.0
{
self.delegate?.callWhileSpeedChange(networkStatus: .poor)
}
else
{
self.delegate?.callWhileSpeedChange(networkStatus: .good)
}
})
}
}
extension NetworkSpeedTest: URLSessionDataDelegate, URLSessionDelegate {
func testDownloadSpeed(withTimout timeout: TimeInterval, completionHandler: #escaping (_ megabytesPerSecond: CGFloat, _ error: Error?) -> Void) {
// you set any relevant string with any file
let urlForSpeedTest = URL(string: testURL!)
startTime = CFAbsoluteTimeGetCurrent()
stopTime = startTime
bytesReceived = 0
speedTestCompletionHandler = completionHandler
let configuration = URLSessionConfiguration.ephemeral
configuration.timeoutIntervalForResource = timeout
let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
guard let checkedUrl = urlForSpeedTest else { return }
session.dataTask(with: checkedUrl).resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
bytesReceived += CGFloat(data.count)
stopTime = CFAbsoluteTimeGetCurrent()
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
let elapsed = (stopTime - startTime) //as? CFAbsoluteTime
let speed: CGFloat = elapsed != 0 ? bytesReceived / (CGFloat(CFAbsoluteTimeGetCurrent() - startTime)) / 1024.0 : -1.0
// treat timeout as no error (as we're testing speed, not worried about whether we got entire resource or not
if error == nil || ((((error as NSError?)?.domain) == NSURLErrorDomain) && (error as NSError?)?.code == NSURLErrorTimedOut) {
speedTestCompletionHandler?(speed, nil)
}
else {
speedTestCompletionHandler?(speed, error)
}
}
}
After That how to use it.So implement delegate and use it.
class ViewController: UIViewController, NetworkSpeedProviderDelegate {
func callWhileSpeedChange(networkStatus: NetworkStatus) {
switch networkStatus {
case .poor:
break
case .good:
break
case .disConnected:
break
}
}
let test = NetworkSpeedTest()
override func viewDidLoad() {
super.viewDidLoad()
test.delegate = self
test.networkSpeedTestStop()
test.networkSpeedTestStart(UrlForTestSpeed: "Paste Your Any Working URL ")
// Do any additional setup after loading the view.
}
}
You can call the Reachability class every time after a fixed interval by using method given below:
override func viewDidLoad() {
scheduledTimerWithTimeInterval()
}
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 'x' seconds
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateCounting), userInfo: nil, repeats: true)
}
#objc func updateCounting(){
\\Do your stuff here(Check Reachabilty Here)
}
EDIT:
This is how you can check signal strength for cellular networks.
func getSignalStrength() -> Int {
let application = UIApplication.shared
let statusBarView = application.value(forKey: "statusBar") as! UIView
let foregroundView = statusBarView.value(forKey: "foregroundView") as! UIView
let foregroundViewSubviews = foregroundView.subviews
var dataNetworkItemView:UIView? = nil
for subview in foregroundViewSubviews {
if subview.isKind(of: NSClassFromString("UIStatusBarSignalStrengthItemView")!) {
dataNetworkItemView = subview
break
}
}
if dataNetworkItemView == nil
{
return 0
}
return dataNetworkItemView?.value(forKey: "signalStrengthBars") as! Int
}
For Wifi Network this is how you can get signal strength
private func getWiFiRSSI() -> Int? {
let app = UIApplication.shared
var rssi: Int?
let exception = tryBlock {
guard let statusBar = app.value(forKey: "statusBar") as? UIView else { return }
if let statusBarMorden = NSClassFromString("UIStatusBar_Modern"), statusBar .isKind(of: statusBarMorden) { return }
guard let foregroundView = statusBar.value(forKey: "foregroundView") as? UIView else { return }
for view in foregroundView.subviews {
if let statusBarDataNetworkItemView = NSClassFromString("UIStatusBarDataNetworkItemView"), view .isKind(of: statusBarDataNetworkItemView) {
if let val = view.value(forKey: "wifiStrengthRaw") as? Int {
rssi = val
break
}
}
}
}
if let exception = exception {
print("getWiFiRSSI exception: \(exception)")
}
return rssi
}
EDIT 2: Add this extension to access your status bar view
extension UIApplication {
var statusBarUIView: UIView? {
if #available(iOS 13.0, *) {
let tag = 38482458385
if let statusBar = self.keyWindow?.viewWithTag(tag) {
return statusBar
} else {
let statusBarView = UIView(frame: UIApplication.shared.statusBarFrame)
statusBarView.tag = tag
self.keyWindow?.addSubview(statusBarView)
return statusBarView
}
} else {
if responds(to: Selector(("statusBar"))) {
return value(forKey: "statusBar") as? UIView
}
}
return nil
}
}
I am trying to detect the percentage of time that the Main thread is busy so I can log this metric when a user is using the app. Currently, the closest thing I can find is the user_time from basic_info with the help from an answer here but how can i know what thread is being used and if its the main thread? Then from here how can i tell how much of that time as a percentage of the apps total run time for that session?
So i managed to figure this out using the following:
class MainThreadAnalyser {
typealias SumTotal = (total: Double, elements: Double)
private var threadPercentages = [Double]()
private let timeIntervalSeconds: Double
init(timeIntervalSeconds: Double) {
self.timeIntervalSeconds = timeIntervalSeconds
if #available(iOS 10.0, *) {
self.startCPUMonitoring(timeIntervalSeconds: self.timeIntervalSeconds)
}
}
func getAverageCpuUsage() -> Double? {
let sumTotal = threadPercentages.reduce((total: 0, elements: 0)) { (sum, item) -> SumTotal in
var result = sum
if item > 0 {
result.total += item
result.elements += 1
}
return result
}
return sumTotal.elements > 0 ? sumTotal.total / sumTotal.elements : nil
}
#available(iOS 10.0, *)
private func startCPUMonitoring(timeIntervalSeconds: Double) {
Timer.scheduledTimer(withTimeInterval: timeIntervalSeconds, repeats: true) { [weak self] _ in
guard let strongSelf = self else { return }
if let cpuUsage = strongSelf.cpuUsage() {
strongSelf.threadPercentages.append(cpuUsage)
}
}
}
private func cpuUsage() -> Double? {
var kernReturn: kern_return_t
var taskInfoCount: mach_msg_type_number_t
taskInfoCount = mach_msg_type_number_t(TASK_INFO_MAX)
var tinfo = [integer_t](repeating: 0, count: Int(taskInfoCount))
kernReturn = task_info(mach_task_self_, task_flavor_t(TASK_BASIC_INFO), &tinfo, &taskInfoCount)
if kernReturn != KERN_SUCCESS {
return -1
}
var threadArray: thread_act_array_t? = UnsafeMutablePointer(mutating: [thread_act_t]())
var threadCount: mach_msg_type_number_t = 0
defer {
if let threadArray = threadArray {
vm_deallocate(mach_task_self_, vm_address_t(UnsafePointer(threadArray).pointee), vm_size_t(threadCount))
}
}
kernReturn = task_threads(mach_task_self_, &threadArray, &threadCount)
if kernReturn != KERN_SUCCESS {
return -1
}
var totalCPU: Double?
if let threadArray = threadArray {
for index in 0 ..< Int(threadCount) {
var threadInfoCount = mach_msg_type_number_t(THREAD_INFO_MAX)
var thinfo = [integer_t](repeating: 0, count: Int(threadInfoCount))
kernReturn = thread_info(threadArray[index], thread_flavor_t(THREAD_BASIC_INFO),
&thinfo, &threadInfoCount)
if kernReturn != KERN_SUCCESS {
return -1
}
if index == 0 {
let cpuUse = thinfo[4]
totalCPU = Double(cpuUse/10)
}
}
}
return totalCPU
}
}
The main thread is being used constantly while the app is in the foreground.
So you can schedule a timer in applicationDidBecomeActive and invalidate in applicationWillResignActive and get the accumulated seconds whenever you want.
i have write the follwing code for my function but i failed to execute iterations after delaying.
I want iterations with delay, for example when loop completed execution till i =2 after this when i == 3 this should execute after some delay.
Please guide me to solve this problem.
func allCellsAttempted() -> Bool {
var allCellsAttempted = true
var count = 0
if !oldVersionTriggered {
count = micSources.count
}
else {
count = olderVersionMicSources.count
}
print("Total Mics : \(count)")
for i in 0..<count {
if let cell = micTestFaliureTableView.cellForRow(at: IndexPath(row: i, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
break
}
}
}
return allCellsAttempted
}
You could use a timer. You will need to pass a completion handler closure to your function to access the result.
I would also suggest you access the information from the underlying data model rather than from the table view cells.
func allCellsAttempted(_ completion: #escaping(_ attempted: Bool)-> Void) -> Void {
var allCellsAttempted = true
var count = 0
var target: Int
if !oldVersionTriggered {
target = micSources.count
}
else {
target = olderVersionMicSources.count
}
print("Total Mics : \(target)")
let _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] (timer) in
guard let strongSelf = self else {
timer.invalidate()
return
}
if let cell = strongSelf.micTestFaliureTableView.cellForRow(at: IndexPath(row: count, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
}
}
count += 1
if count == target || !allCellsAttempted {
timer.invalidate()
completion(allCellsAttempted)
}
}
}
Try to use
DispatchQueue.main.asyncAfter(deadline:.now() + 2.0, execute: { })
i Want to get file in Input Stream From Socket In swift
There are many examples to get a string from the socket but did not find any method to get a socket file
// To connect to the server
func connect(host: String, port: Int) {
SwifterHandler.sharedInstance.FilePathSave = SwifterHandler.sharedInstance.rootDoc()
self.host = host
self.port = port
Stream.getStreamsToHost(withName: host, port: port, inputStream: &self.inputStream, outputStream: &self.outputStream)
if self.inputStream != nil && self.outputStream != nil {
self.inputStream!.delegate = self
self.outputStream!.delegate = self
self.inputStream!.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
self.outputStream!.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
self.inputStream!.open()
self.outputStream!.open()
}
}
// This is a call back func that takes care of I/O from/to the server.
// Read about this func. There are many event codes to handle.
// I just wanted to make it simple.
func stream(aStream: Stream, handleEvent eventCode: Stream.Event) {
print("Event : \(eventCode)")
if aStream != inputStream {
return
}
if eventCode == .hasBytesAvailable {
self.ReadFile()
}
}
private func ReadFile()
{
var buffer = [UInt8](repeating: 0, count: 1024)
if let fh = FileHandle(forWritingAtPath: "\(SwifterHandler.sharedInstance.FilePathSave)/test.png") {
fh.seekToEndOfFile()
while (self.inputStream!.hasBytesAvailable){
let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
fh.write(Data(bytes: buffer))
}
}
fh.closeFile()
}
SwifterHandler.sharedInstance.SharedFile(path: SwifterHandler.sharedInstance.FilePathSave)
self.dataReadCallback!("Success Download")
InstallApp().InstallApplication()
self.dataReadCallback!("Application Installed")
}
ReadFile() do not run when server send file
class ViewController: UIViewController,StreamDelegate
{
var inputstream: InputStream?
var outputstream: OutputStream?
var host: String?
var port: Int?
override func viewDidLoad()
{
super.viewDidLoad()
let _ = initNetworkCommunication()
let word = "Hello are you there->"
let buf = [UInt8](word.utf8)
print("This is buf = \(buf))")
outputstream?.write(buf, maxLength: buf.count)
}
func initNetworkCommunication()
{
host = "127.0.0.1" //this is IP number passing as string
port = 34 //this is port number
Stream.getStreamsToHost(withName: host!, port: port!,inputStream: &inputstream, outputStream: &outputstream)
//here we are going to calling a delegate function
inputstream?.delegate = self as? StreamDelegate
outputstream?.delegate = self as? StreamDelegate
inputstream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
outputstream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
inputstream?.open()
print("Here the input stream will open")
outputstream?.open()
print("connected")
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event)
{
print("we are in delegate method")
print("EventCode = \(eventCode)")
switch (eventCode)
{
case Stream.Event.openCompleted:
if(aStream == outputstream)
{
print("output:OutPutStream opened")
}
print("Input = openCompleted")
break
case Stream.Event.errorOccurred:
if(aStream === outputstream)
{
print("output:Error Occurred\n")
}
print("Input : Error Occurred\n")
break
case Stream.Event.endEncountered:
if(aStream === outputstream)
{
print("output:endEncountered\n")
}
print("Input = endEncountered\n")
break
case Stream.Event.hasSpaceAvailable:
if(aStream === outputstream)
{
print("output:hasSpaceAvailable\n")
}
print("Input = hasSpaceAvailable\n")
break
case Stream.Event.hasBytesAvailable:
if(aStream === outputstream)
{
print("output:hasBytesAvailable\n")
}
if aStream === inputstream
{
print("Input:hasBytesAvailable\n")
var buffer = [UInt8](repeating: 0, count: 4096)
//print("input buffer = \(buffer)")
// sleep(40)
while (self.inputstream!.hasBytesAvailable)
{
let len = inputstream!.read(&buffer, maxLength: buffer.count)
// If read bytes are less than 0 -> error
if len < 0
{
let error = self.inputstream!.streamError
print("Input stream has less than 0 bytes\(error!)")
//closeNetworkCommunication()
}
// If read bytes equal 0 -> close connection
else if len == 0
{
print("Input stream has 0 bytes")
// closeNetworkCommunication()
}
if(len > 0)
//here it will check it out for the data sending from the server if it is greater than 0 means if there is a data means it will write
{
let messageFromServer = NSString(bytes: &buffer, length: buffer.count, encoding: String.Encoding.utf8.rawValue)
if messageFromServer == nil
{
print("Network hasbeen closed")
// v1.closeNetworkCommunication()
}
else
{
print("MessageFromServer = \(String(describing: messageFromServer))")
}
}
}
}
break
default:
print("default block")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am writing a very, very simple TCP socket app that sends and receives data from a server; my app uses delegates; most of the code I found from online but none of the event handlers for the streams are working; any ideas on why the following method is never being called?
UPDATE: this question has been answered here:
Non-responsive stream delegate in Swift
However, the problem that I am facing is how do I flush the output stream after the buffer is full? I would like send data in real time to my server, but I am getting a "broken pipe" from stream output error
/**
NSStream Delegate Method where we handle errors, read and write data from input and output streams
:param: stream NStream that called delegate method
:param: eventCode Event Code
*/
final func stream(stream: Stream, handleEvent eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.endEncountered:
endEncountered(stream: stream)
case Stream.Event.errorOccurred:
print("[SCKT]: ErrorOccurred: \(stream.streamError?.localizedDescription)")
case Stream.Event.openCompleted:
print("open completed")
openCompleted(stream: stream)
case Stream.Event.hasBytesAvailable:
handleIncommingStream(stream: stream)
case Stream.Event.hasSpaceAvailable:
print("space available")
writeToStream()
default:
print("default!")
}
}
UIViewController
import Darwin
import Foundation
import UIKit
import Dispatch
class ViewController: UIViewController {
#IBOutlet private weak var joystickMove: Joystick!
#IBOutlet private weak var joystickRotate: Joystick!
private var joystick = Joystick()
private var contour = Contours()
private var contour_index: Int = 0
private var ip_address = "000.000.00.0" as CFString
private var port: Int = 0000
private var control_socket: Socket
// private var control_socket: Socket = Socket()
private var toast_label: UILabel = UILabel()
// let dataProcessingQueue = DispatchQueue.main
// convenience init() {
// self.control_socket = Socket()
// }
// init(coder aDecoder: NSCoder!) {
// super.init(coder: aDecoder)
// }
// init(imageURL: NSURL?) {
// self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
// super.init(nibName: nil, bundle: nil)
// }
// required init?(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
// }
required init(coder aDecoder: NSCoder) {
print("here!")
self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
print("here(2)!")
super.init(coder: aDecoder)!
}
override func viewDidLoad() {
super.viewDidLoad()
self.control_socket.open(host: self.ip_address as String!, port: self.port)
createJoystick()
createContours()
createViewsButton()
recvLidarData()
}
private func requestIsComplete() -> Bool {
// This function should find out if all expected data was received and return 'true' if it did.
return true
}
private func processData(data: Data) {
// This function should do something with the received data
}
private func recvLidarData() {
let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.async {
// recieve the data here!
}
}
private func createToast() {
self.toast_label = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 150, y: self.view.frame.size.height-100, width: 300, height: 35))
self.toast_label.backgroundColor = UIColor.black
self.toast_label.textColor = UIColor.white
self.toast_label.textAlignment = NSTextAlignment.center;
self.view.addSubview(self.toast_label)
self.toast_label.text = "Could not connect to server"
self.toast_label.alpha = 1.0
self.toast_label.layer.cornerRadius = 10;
self.toast_label.clipsToBounds = true
UIView.animate(withDuration: 4.0, delay: 0.1, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.toast_label.alpha = 0.0
})
}
private func createJoystick() {
let n: CGFloat = 100.0
let x: CGFloat = (UIScreen.main.bounds.width/2) - (n/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0)
self.joystick.frame = CGRect(x: x, y: y, width: n, height: n)
self.joystick.backgroundColor = UIColor.clear
self.joystick.substrateColor = UIColor.lightGray
self.joystick.substrateBorderColor = UIColor.gray
self.joystick.substrateBorderWidth = 1.0
self.joystick.stickSize = CGSize(width: 50.0, height: 50.0)
self.joystick.stickColor = UIColor.darkGray
self.joystick.stickBorderColor = UIColor.black
self.joystick.stickBorderWidth = 2.0
self.joystick.fade = 0.5
self.joystick.ip_address = self.ip_address
self.joystick.port = self.port
var packet = ""
DispatchQueue.global(qos: .userInitiated).async { // do some task
// self.control_socket = Socket()
// self.control_socket.open(host: self.ip_address as String!, port: self.port)
self.joystick.trackingHandler = { (data) -> () in
var power = sqrt(pow(Double(data.velocity.x), 2.0) + pow(Double(data.velocity.y), 2.0))
let theta = atan2(Double(-data.velocity.y), Double(data.velocity.x))
let degrees = theta * (180.0 / M_PI)
power = power/1.2
if degrees >= 55 && degrees <= 125 { // move forward
packet = "\(1) \(1) \(power) \(power)"
} else if degrees >= -125 && degrees <= -55 { // move backwards
packet = "\(-1) \(-1) \(power) \(power)"
} else if degrees >= -55 && degrees <= 55 { // turn right
packet = "\(1) \(-1) \(power) \(power)"
} else { // turn left
packet = "\(-1) \(1) \(power) \(power)"
}
}
print("packet: \(packet)")
self.control_socket.send(message: packet)
print("sent")
}
view.addSubview(joystick)
}
private func createContours() {
let n: CGFloat = 350.0
let x: CGFloat = (UIScreen.main.bounds.width/2.0) - (n/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0) - n - 100.0
self.contour.frame = CGRect(x: x, y: y, width: n, height: n)
self.contour.backgroundColor = UIColor.clear
view.addSubview(self.contour)
}
private func createViewsButton() {
let width: CGFloat = 150.0
let height: CGFloat = 75.0
let x: CGFloat = (UIScreen.main.bounds.width/2.0) - (width/2.0)
let y: CGFloat = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/4.0) - width
let button: UIButton = UIButton(frame: CGRect(x: x, y: y, width: width, height: height))
button.backgroundColor = UIColor.blue
button.setTitle("Contour Views", for: .normal)
button.addTarget(self, action: #selector(self.buttonAction), for: .touchUpInside)
button.tag = 1
view.addSubview(button)
}
#objc private func buttonAction(sender: UIButton!) {
var btnsendtag: UIButton = sender
if btnsendtag.tag == 1 {
self.contour_index = (self.contour_index + 1) % 2
switch self.contour_index {
case 0:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 0
}
}
case 1:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 1
}
}
default:
for index in 0...356 {
if self.contour.distx[index] != -1 && self.contour.disty[index] != -1 {
self.contour.circles[index].alpha = 1
UIColor.cyan.setFill()
self.contour.lines[index].fill()
self.contour.lines[index].stroke()
}
}
}
}
}
override func viewDidAppear(_ animated: Bool) {
}
public func delayWithSeconds(_ seconds: Double, completion: #escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
completion()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(_ animated: Bool) {
}
}
Socket class
import UIKit
import Foundation
#objc protocol SocketStreamDelegate{
func socketDidConnect(stream:Stream)
#objc optional func socketDidDisconnet(stream:Stream, message:String)
#objc optional func socketDidReceiveMessage(stream:Stream, message:String)
#objc optional func socketDidEndConnection()
}
class Socket: NSObject, StreamDelegate {
var delegate:SocketStreamDelegate?
private let bufferSize = 1024
private var _host:String?
private var _port:Int?
private var _messagesQueue:Array<String> = [String]()
private var _streamHasSpace:Bool = false
private var inputStream: InputStream?
private var outputStream: OutputStream?
var isClosed = false
var isOpen = false
var host:String?{
get{
return self._host
}
}
var port:Int?{
get{
return self._port
}
}
deinit{
if let inputStr = self.inputStream{
inputStr.close()
inputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
if let outputStr = self.outputStream{
outputStr.close()
outputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
}
/**
Opens streaming for both reading and writing, error will be thrown if you try to send a message and streaming hasn't been opened
:param: host String with host portion
:param: port Port
*/
final func open(host:String!, port:Int!){
self._host = host
self._port = port
var inStreamUnmanaged:Unmanaged<CFReadStream>?
var outStreamUnmanaged:Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(nil, host as CFString!, UInt32(port), &inStreamUnmanaged, &outStreamUnmanaged)
inputStream = inStreamUnmanaged?.takeRetainedValue()
outputStream = outStreamUnmanaged?.takeRetainedValue()
if inputStream != nil && outputStream != nil {
inputStream!.delegate = self
outputStream!.delegate = self
// var myloop = RunLoop.current
// inputStream!.schedule(in: myloop, forMode: RunLoopMode.defaultRunLoopMode)
// outputStream!.schedule(in: myloop, forMode: RunLoopMode.defaultRunLoopMode)
inputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
outputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
print("[SCKT]: Open Stream")
self._messagesQueue = Array()
inputStream!.open()
outputStream!.open()
// myloop.run()
print("Run")
} else {
print("[SCKT]: Failed Getting Streams")
}
}
final func close(){
if let inputStr = self.inputStream {
inputStr.delegate = nil
inputStr.close()
inputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
if let outputStr = self.outputStream {
outputStr.delegate = nil
outputStr.close()
outputStr.remove(from: .main, forMode: RunLoopMode.defaultRunLoopMode)
}
isClosed = true
}
/**
NSStream Delegate Method where we handle errors, read and write data from input and output streams
:param: stream NStream that called delegate method
:param: eventCode Event Code
*/
final func stream(stream: Stream, handleEvent eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.endEncountered:
endEncountered(stream: stream)
case Stream.Event.errorOccurred:
print("[SCKT]: ErrorOccurred: \(stream.streamError?.localizedDescription)")
case Stream.Event.openCompleted:
print("open completed")
openCompleted(stream: stream)
case Stream.Event.hasBytesAvailable:
handleIncommingStream(stream: stream)
case Stream.Event.hasSpaceAvailable:
print("space available")
writeToStream()
default:
print("default!")
}
}
final func endEncountered(stream: Stream) {
}
final func openCompleted(stream: Stream){
if(self.inputStream!.streamStatus == .open && self.outputStream!.streamStatus == .open) {
let justAOneTimeThing: () = {
self.isOpen = true
self.delegate!.socketDidConnect(stream: stream)
}()
}
}
/**
Reads bytes asynchronously from incomming stream and calls delegate method socketDidReceiveMessage
:param: stream An NSInputStream
*/
final func handleIncommingStream(stream: Stream) {
if stream is InputStream {
var buffer = [UInt8](repeating: 0, count: bufferSize)
DispatchQueue.global(qos: .userInitiated).async {
let len = self.inputStream?.read(&buffer, maxLength: buffer.count)
if len! >= 0 {
if let output = NSString(bytes: &buffer, length: len!, encoding: String.Encoding.utf8.rawValue) {
self.delegate?.socketDidReceiveMessage!(stream: stream, message: output as String)
}
} else {
// Handle error
}
}
} else {
print("[SCKT]: \(#function) : Incorrect stream received")
}
}
/**
If messages exist in _messagesQueue it will remove and it and send it, if there is an error
it will return the message to the queue
*/
final func writeToStream() {
if _messagesQueue.count > 0 && self.outputStream!.hasSpaceAvailable {
DispatchQueue.global(qos: .userInitiated).async {
let message = self._messagesQueue.removeLast()
let buff = [UInt8](message.utf8)
if self.outputStream!.write(buff, maxLength: buff.count) == -1 {
self._messagesQueue.append(message)
}
}
}
}
final func send(message:String){
_messagesQueue.insert(message, at: 0)
writeToStream()
}
}
Maybe your stream function prototype is incorrect. Your prototype is
final func stream(stream: Stream, handleEvent eventCode: Stream.Event)
Try this:
func stream(_ aStream: Stream, handle eventCode: Stream.Event)
in your Socket class