Delegated functions not working outside of UIViewController - ios

I'm using the Startscream Websocket framework. Everything works fine as long as I keep all of the code in a UIViewController as seen here. But as soon as a create a wrapper class for Startscream all of the delegated functions stop working. Also my local websocket server is not getting a connection.
How can I get the code working inside a wrapper class?
MyService.swift:
import Starscream
public class MyService: WebSocketDelegate {
var socket = WebSocket(url: URL(string: "ws://localhost:3900/websocket")!)
func connect() {
socket.delegate = self
socket.connect()
print("Connecting")
}
// MARK: Websocket Delegate Methods.
public func websocketDidConnect(socket: WebSocket) {
print("websocket is connected")
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
print("Received text: \(text)")
}
public func websocketDidReceiveData(socket: WebSocket, data: Data) {
print("Received data: \(data.count)")
}
// MARK: Write Text Action
#IBAction func writeText(_ sender: UIBarButtonItem) {
socket.write(string: "hello there!")
}
// MARK: Disconnect Action
#IBAction func disconnect(_ sender: UIBarButtonItem) {
if socket.isConnected {
sender.title = "Connect"
socket.disconnect()
} else {
sender.title = "Disconnect"
socket.connect()
}
}
}
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let service = MyService()
service.connect()
}
}

The reference to Service in ViewController was not stored anywhere so as soon as the function was run it was cleaned up. This is how I fixed it:
class ViewController: UIViewController {
var service = MyService()
override func viewDidLoad() {
super.viewDidLoad()
service.connect()
}
...

I'm not sure what is wrong with your code, it can be an endpoint issue, or WS is not allocated somehow. I have same code with Starscream working in Swift 3, here is the main part of my class.
class ConnectionManager {
private var savedSocket: WebSocket?
fileprivate var socket: WebSocket {
if let saved = savedSocket {
return saved
}
let wsURL = URL(string: UserDefaultsManager.wsURLString)!
savedSocket = WebSocket(url: wsURL)
return savedSocket!
}
func startSession() {
if (socket.isConnected) { return }
socket.headers = headers
socket.delegate = self
socket.connect()
}
func endSession() {
if (socket.isConnected) {
socket.disconnect()
}
}
}
extension ConnectionManager: WebSocketDelegate {
func websocketDidConnect(socket: WebSocket) {
}
func websocketDidDisconnect(socket: WebSocket, error: NSError?){
if let e = error {
log.error("websocket is disconnected with ERROR: \(e.localizedDescription)")
} else {
log.error("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocket, text: String){
}
func websocketDidReceiveData(socket: WebSocket, data: Data){
}
}
My code is not a best practise for sure, but it works without any problem. Try to use my version, maybe it will work for you.

Related

Sinch Video calling sound is coming from front speaker

I have implemented sinch video calling in ios swift project i have followed all process given in sinch implementation document https://www.sinch.com/docs/video/ios/#calling. And i am successfully able to implement but i am getting on issue my video sound in coming from front speaker. how can i solve this problem?? Below my code:
var client: SINClient?
var sinCall : SINCall?
Configuring sinch
//MARK: Configuring Sinch Delegate
func configuringSinch(){
//Configuring Client Key
client = Sinch.client(withApplicationKey: Constants.SINCH_APP_KEY, applicationSecret: Constants.SINCH_PRIVATE_KEY, environmentHost: Constants.SANDBOX_ENVIRONMENT, userId: Utility().getUserId())
client?.call().delegate = self
client?.setSupportCalling(true)
client?.enableManagedPushNotifications()
client?.start()
client?.startListeningOnActiveConnection()
let vcCont = client?.videoController()
self.vwLocalView.addSubview((vcCont?.localView())!)
self.sinCall?.delegate = self
}
//MARK: Sinch Video Call Delegate
func clientDidStart(_ client: SINClient!) {
print("Client Did Start")
}
func clientDidFail(_ client: SINClient!, error: Error!) {
print("Client failed : \(error)")
player?.stop()
}
func clientDidStop(_ client: SINClient!) {
print("Client Did Stop")
player?.stop()
}
//MARK: Video Call Did Recieve
func client(_ client: SINCallClient!, didReceiveIncomingCall call: SINCall!) {
print("Did Recieve Incoming Call")
playRingtoneSound() // Playing Audio
call.delegate = self;
self.sinCall = call
}
//MARK: Call Did Add Video Track
func callDidAddVideoTrack(_ call: SINCall!) {
let videoCont = client?.videoController()
vwRemoteView.addSubview((videoCont?.remoteView())!)
}
func callDidEnd(_ call: SINCall!) {
sinCall?.hangup()
}
This is how you can manage SINAudioController to manage audio output.
func audioController() -> SINAudioController {
return (client?.audioController())!
}
//MARK: Video Call Did Recieve
func client(_ client: SINCallClient!, didReceiveIncomingCall call: SINCall!) {
audioController().enableSpeaker()
playRingtoneSound() // Playing Audio
call.delegate = self;
self.sinCall = call
}
// In SINCallDelegate
func callDidEstablish(_ call: SINCall!) {
//to disableSpeaker
audioController().disableSpeaker()
}
try this to manage AudioOutput Session manually
// MARK: AudioOutput Session
// to enable front speaker manually
func setSessionPlayerOn()
{
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSessionPortOverride.none)
} catch _ {
}
}
// to enable speaker manually
func setSessionPlayerSpeaker()
{
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
} catch _ {
}
}
// to turnoff AudioOutput Session manually
func setSessionPlayerOff()
{
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch _ {
}
}
Use this function
func callDidEstablish(_ call: SINCall!) {
let audio = APPDELEGATE.client?.audioController()
audio?.disableSpeaker()
// self.startCallDurationTimerWithSelector()
appDelegate.client?.audioController().stopPlayingSoundFile()
}
this is work for me.
class MainVC: UIViewController,SINCallDelegate {
// var client: SINClient?
private let videoController = SinchManager.sharedInstance.client!.videoController()
private let audioController = SinchManager.sharedInstance.client!.audioController()
private let callClient: SINCallClient
private var call: SINCall!
let username: String
#IBOutlet weak var otherView: UIView!
// private var mainView: SinchView { return view as! SinchView }
#IBAction func call_btn(_ sender: UIButton) {
answer()
}
#IBAction func end_btn(_ sender: UIButton) {
decline()
}
override func loadView() {
// view = SinchView()
view = otherView
}
init(username: String) {
self.username = username
self.callClient = SinchManager.sharedInstance.client!.call()
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
print("init(coder:) has not been implemented " + String(describing: aDecoder))
fatalError("init(coder:) has not been implemented " + String(describing: aDecoder))
}
override func viewDidLoad() {
super.viewDidLoad()
call.delegate = self
//self.mainView.videoView.addSubview(self.videoController.localView())
otherView.addSubview((self.videoController?.localView())!)
self.videoController?.localView().contentMode = .scaleToFill
if self.call.direction == SINCallDirection.incoming {
self.audioController?.startPlayingSoundFile(self.pathForSound(string: "incoming.wav") as String, loop: true)
}
if self.call.details.isVideoOffered {
print("video offered")
//self.mainView.videoView.addSubview(self.videoController.localView())
otherView.addSubview((self.videoController?.localView())!)
self.videoController?.localView().contentMode = .scaleToFill
}
otherView.addSubview((self.videoController?.localView())!)
// mainView.answerButton.addTarget(self, action: #selector(answer), forControlEvents: .TouchUpInside)
// mainView.declineButton.addTarget(self, action: #selector(decline), forControlEvents: .TouchUpInside)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.audioController?.enableSpeaker()
}
func pathForSound(string: String) -> NSString {
let nsSt = Bundle.main.resourcePath! as NSString
return nsSt.appendingPathComponent(string) as NSString
}
func answer() {
call.answer()
}
func decline() {
call.hangup()
}
func callDidEstablish(call: SINCall!) {
print("callDidEstablish")
let audio = SinchManager.sharedInstance.client!.audioController()
audio?.disableSpeaker()
// self.startCallDurationTimerWithSelector()
SinchManager.sharedInstance.client!.audioController().stopPlayingSoundFile()
}
func callDidEnd(call: SINCall!) {
print("callDidEnd")
}
func callDidProgress(call: SINCall!) {
print("callDidProgress")
self.audioController?.startPlayingSoundFile(self.pathForSound(string: "ringback.wav") as String, loop: true)
}
func callDidAddVideoTrack(call: SINCall!) {
print("callDidAddVideoTrack")
otherView.addSubview((self.videoController?.localView())!)
}

Use a protocol between a class and a view controller Swift 3

I worked with the library SwiftSocket to send messages to my server. When the connexion is established I want to create a callback to catch results. But my protocol is always null and the callback is not send.
This is my TCPClient class :
protocol ProtocolTCPClient {
func connexionSucceeded()
}
class UtilsTCPClient {
var delegate: ProtocolTCPClient?
let client: TCPClient?
init(address: String, port: Int32) {
client = TCPClient(address: address, port: port)
switch client!.connect(timeout: 5) {
case .success:
print("Success")
if(delegate != nil){
self.delegate?.connexionSucceeded()//never called
} else{
print("delegate nil")
}
case .failure(let error):
print("Error: ")
print(error)
}
}
}
This is my ViewController
import UIKit
import SwiftSocket
class ViewController: UIViewController, ProtocolTCPClient {
var client: UtilsTCPClient?
override func viewDidLoad() {
super.viewDidLoad()
self.client = UtilsTCPClient(address: "server", port: 80)
self.client?.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connexionSucceeded(){
print("Connexion succeeded")//never called
}
}
Thank you for your answers
your code should look like this.Because in your code first you init 'UtilsTCPClient' and then assigning delegate. And in 'UtilsTCPClient' you create 'TCPClient' and trying to access delegate but till it't not assigned so you should try the below code.
protocol ProtocolTCPClient {
func connexionSucceeded()
}
class UtilsTCPClient {
var delegate: ProtocolTCPClient?
let client: TCPClient?
init(address: String, port: Int32, delegate: ProtocolTCPClient) {
self.delegate = delegate
client = TCPClient(address: address, port: port)
switch client!.connect(timeout: 5) {
case .success:
print("Success")
if(delegate != nil){
self.delegate?.connexionSucceeded()
} else{
print("delegate nil")
}
case .failure(let error):
print("Error: ")
print(error)
}
}
}
class ViewController: UIViewController, ProtocolTCPClient {
var client: UtilsTCPClient?
override func viewDidLoad() {
super.viewDidLoad()
self.client = UtilsTCPClient(address: "server", port: 80, delegate: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connexionSucceeded(){
print("Connexion succeeded")//never called
}
}

Starscream delegates not being called

The variable is not nil, I have a good connection and the url is correct but no delegate methods are being called. Also I am implementing WebSocketDelegate
let socket = WebSocket(url: NSURL(string: "UrlHere:port/")!)
socket.delegate = self;
socket.connect()
if socket.isConnected {
print("websocket is connected")
}
func websocketDidConnect(ws: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(ws: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(ws: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(ws: WebSocket, data: NSData) {
print("Received data: \(data.length)")
}
func websocketDidReceivePong(socket: WebSocket) {
print("Got pong!")
}
Socket should be a property or variable of your class to make sure it sticks around.
If you allocate it just on a function stack it will fall out of scope and the delegates will never get called
Here is the code that I have used in my project just in case
import UIKit
//import WebSocket
import Starscream
class ViewController: UIViewController,WebSocketDelegate,WebSocketPongDelegate {
#IBOutlet weak var wsURL: UITextField!
#IBOutlet weak var wsConsole: UITextView!
#IBOutlet weak var wsMessage: UITextField!
var socket:WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
// var webSocketObj:WebSocket = WebSocket()
// webSocketObj.ipAddressText = "10.12.1.101"
// webSocketObj.portText = "8888"
// webSocketObj.dataToSendText = "hi"
// webSocketObj.dataRecievedTextView = ""
// webSocketObj.connectedLabel = ""
// webSocketObj.connectToServer()
wsURL.text="ws://10.12.1.101:8888/"
wsMessage.text="Hi"
self.navigationItem.leftBarButtonItem?.title="Connect"
self.navigationItem.rightBarButtonItem?.enabled=false
// Do any additional setup after loading the view, typically from a nib.
}
func websocketDidConnect(socket: WebSocket){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got connected")
self.navigationItem.leftBarButtonItem?.title="Disconnect"
self.navigationItem.rightBarButtonItem?.enabled=true
}
func websocketDidDisconnect(socket: WebSocket, error: NSError?){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got disconnected")
self.navigationItem.leftBarButtonItem?.title="Connect"
self.navigationItem.rightBarButtonItem?.enabled=false
}
func websocketDidReceiveMessage(socket: WebSocket, text: String){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket got a message from server:").stringByAppendingString(text)
}
func websocketDidReceiveData(socket: WebSocket, data: NSData){
print("websocket received data",data)
}
#IBAction func writeText(sender: UIBarButtonItem) {
wsConsole.text = wsConsole.text .stringByAppendingString("\n Client sent a message:").stringByAppendingString(wsMessage.text!)
socket.writeString(wsMessage.text!)
self.view .endEditing(true)
}
#IBAction func disconnect(sender: UIBarButtonItem) {
self.view .endEditing(true)
if socket == nil{
connect(sender)
}
else if socket.isConnected {
socket.disconnect()
} else {
connect(sender)
}
}
func connect(sender:UIBarButtonItem){
socket = WebSocket(url: NSURL(string:wsURL.text!)!)
socket.delegate = self
socket.connect()
}
func websocketDidReceivePong(socket: WebSocket){
wsConsole.text = wsConsole.text .stringByAppendingString("\n websocket received pong")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is the link to storyboard just in case if you want

Starscream's socket.isConnected is always returning false

I'm developing an iOS application using Swift that connects to an Android device via sockets. I've implemented Starscream and was able to connect to the other device. My issue is that when I print something on the websocketDidConnect delegate method, it does not print. Also when I print socket.isConnected, it prints false. Kindly help me. Thanks. Other alternatives to Starscream are also welcome, thanks!
Here is my code:
import Starscream
class SettingsViewController: UIViewController, UITextFieldDelegate, WebSocketDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let socket = WebSocket(url: NSURL(string: "ws://\(ipAddressTextField.text!):4000/")!)
socket.connect()
print("socket.isConnected \(socket.isConnected)") //this one is false
socket.onConnect = {
print("Connected...") // does not print
}
socket.onDisconnect = { (error: NSError?) in
print("websocket is disconnected: \(error?.localizedDescription)") // this one prints when I turn the wifi off
}
socket.onData = { (data: NSData) in
print("got some data: \(data.length)")
}
}
func websocketDidConnect(ws: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(ws: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(ws: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(ws: WebSocket, data: NSData) {
print("Received data: \(data.length)")
}
}
You need to make it as a class property otherwise it will be released as it gets out of viewDidLoad method.

How to Call Web Service in Web Socket in iOS?

currently i am making chat application using Web Socket.
My question is How to Call Web Service in Web Socket ?
In iOS using swift you can use two Cocoapods Library which makes your work hassle free and
1) Starscream
2) RocketSocket
With reference to Starscream follow are very handy example:
import UIKit
import Starscream
class ViewController: UIViewController, WebSocketDelegate {
var socket: WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
var request = URLRequest(url: URL(string: "http://localhost:8080")!)
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()
}
// MARK: Websocket Delegate Methods.
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let e = error as? WSError {
print("websocket is disconnected: \(e.message)")
} else if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("Received data: \(data.count)")
}
// MARK: Write Text Action
#IBAction func writeText(_ sender: UIBarButtonItem) {
socket.write(string: "hello there!")
}
// MARK: Disconnect Action
#IBAction func disconnect(_ sender: UIBarButtonItem) {
if socket.isConnected {
sender.title = "Connect"
socket.disconnect()
} else {
sender.title = "Disconnect"
socket.connect()
}
}
}

Resources