nuclearace / Socket.IO-Client-Swift

socket.io-client for Swift
Other
361 stars 53 forks source link

socket.connect() command needs to be written twice to connect to server #72

Closed sumairasaeed closed 9 years ago

sumairasaeed commented 9 years ago

Any body experienced this? I noticed that i connected to server when i runned this command twice:

socket.connect()

Also I am unable to get any message from server on client side that i am connected. I have to check Server side messages to check if i am connected. i used following code on client side to check connection:

self.socketObj.socket.on("connect") {data, ack in NSLog("socket connected") } Please help

nuclearace commented 9 years ago

I'd need more information on how you're creating the client. And is there anything special about the server?

sumairasaeed commented 9 years ago

Nothing special about server. Her is the client side code:

@IBAction func loginBtnTapped() {

    //============================ Authenticate User ================
   var url=Constants.MainUrl+Constants.authentictionUrl
    var param:[String:String]=["username": txtForEmail.text!,"password":txtForPassword.text!]
    Alamofire.request(.POST,"\(url)",parameters: param).response{
        request, response, data, error in
        println(error)

       if response?.statusCode==200

        {
            println("login success")
            self.labelLoginUnsuccessful.text=nil
            self.gotToken=true

            //======GETTING REST API TO GET CURRENT USER=======================

            var userDataUrl=Constants.MainUrl+Constants.getCurrentUser
            //let index: String.Index = advance(self.AuthToken.startIndex, 10)

            //======================STORING Token========================
            let jsonLogin = JSON(data: data!)
            let token = jsonLogin["token"]
            self.AuthToken=token.string!

            //========GET USER DETAILS===============
            var getUserDataURL=userDataUrl+"?access_token="+self.AuthToken
            Alamofire.request(.GET,"\(getUserDataURL)").response{
                request1, response1, data1, error1 in

              if response1?.statusCode==200

                {    println("got user success")
                    self.gotToken=true
                    let json = JSON(data: data1!)
                    self.currentUserData=json

                    //===========INITIALISE SOCKETIOCLIENT=========
                    let socket=SocketIOClient(socketURL:"\(url)")
                    socket.connect()

                    socket.on("connect") {data, ack in
                        println("socket connected")
                    }
                    socket.connect()
                    println(socket.connected) //this prints false always
                     self.dismissViewControllerAnimated(true, completion: nil);
                 }
                else
                {
                   println("got user failed")
                    self.labelLoginUnsuccessful.text="Sorry, you are not registered"
                    self.txtForEmail.text=nil
                    self.txtForPassword.text=nil
                }
            }
         }

        else
        {
           println("login failed")
            self.labelLoginUnsuccessful.text="Sorry, you are not registered"
            self.txtForEmail.text=nil
            self.txtForPassword.text=nil
        }
    }
}
sumairasaeed commented 9 years ago

When i write socket.connect() twice, then server prints message of CONNECTED. It does not print CONNECTED on server-side if I write socket.connect() once. And in both cases, no message of 'connected' is printed on client side.

nuclearace commented 9 years ago

Hm, it looks like you're calling the connect inside a callback. I wonder if it's something like the callback is called on something other than the main queue.

sumairasaeed commented 9 years ago

This function is called when a LOGIN button is tapped from main screen

nuclearace commented 9 years ago

Can you turn on logging for the socket?

let socket = SocketIOClient(socketURL: "blah", opts: ["log": true])
nuclearace commented 9 years ago

Doesn't seem to be a queue issue.

nuclearace commented 9 years ago

Oh wait, I just noticed in your example you have the socket declared as a local variable. This isn't what you want to do. It needs to be a property of an object, otherwise it'll be deallocated as soon as it goes out of scope.

sumairasaeed commented 9 years ago

I have just made it property of another class. And turned on logging. received following msgs on console:

got user success 2015-08-20 00:42:43.863 Chat[4841:226682] SocketClient: Adding engine 2015-08-20 00:42:43.871 Chat[4841:226682] SocketEngine: Starting engine false2015-08-20 00:42:43.872 Chat[4841:226682] SocketEngine: Handshaking

2015-08-20 00:42:43.873 Chat[4841:226682] SocketEngine: Doing polling request 2015-08-20 00:42:43.874 Chat[4841:226682] SocketClient: Adding handler for event: connect 2015-08-20 00:42:44.386 Chat[4841:226692] SocketClient: Client is being deinit 2015-08-20 00:42:44.386 Chat[4841:226692] SocketEngine: Engine is being closed. Fast: 1 2015-08-20 00:42:44.387 Chat[4841:226692] SocketEngine: Engine is being deinit

nuclearace commented 9 years ago

Yeah, it's being deallocated

sumairasaeed commented 9 years ago

i have made a class like this and made socket as its property:

class LoginAPI{

var socket:SocketIOClient
init(){
    socket=SocketIOClient(socketURL: "")
}

func connect(url:String){
    socket=SocketIOClient(socketURL: "\(url)",opts: ["log": true])
}

func getSocket()->SocketIOClient{
    return self.socket
}

}

nuclearace commented 9 years ago

What holds onto that object? If it's on a view controller that's being dismissed there's a good chance that it will also be deallocated. You'd need to put the object somewhere persistent.

sumairasaeed commented 9 years ago

i declared it globally like this in my viewController class

class LoginViewController: UIViewController, UITextFieldDelegate{ var socketObj=LoginAPI() //........

then in login button tabbed method, i coded like this

@IBAction func loginBtnTapped() {
//......

if response1?.statusCode==200

                {    println("got user success")
                    self.gotToken=true
                    let json = JSON(data: data1!)
                    self.currentUserData=json

                    //===========INITIALISE SOCKETIOCLIENT=========
                    self.socketObj.connect("\(url)")
                    self.socketObj.socket.connect()

                    self.socketObj.socket.on("connect") {data, ack in
                        println("socket connected")
                    }

                    println(self.socketObj.socket.connected) //this prints false always

                }

//...

}

nuclearace commented 9 years ago

Does the LoginController get dismissed shortly after the login button is clicked?

sumairasaeed commented 9 years ago

yes.

nuclearace commented 9 years ago

Then it's probably getting deallocated with that viewcontroller.

sumairasaeed commented 9 years ago

Thanks lot for your help.

sumairasaeed commented 9 years ago

You are right. Will see where i can keep socket object to be persistent

cesar-oyarzun-m commented 9 years ago

@sumairasaeed Hey I'm trying to do something similar, How can I pass the socket object to a child element, I have this code

public  class TestSocket: NSObject {
public var socket = SocketIOClient(socketURL: hostUrl, options: ["log": false,"connectParams": ["token":tokenSDK]])

then I inherit form TestSocket and I just want to override method

public final class TestSystemCh: TestSocket {
override public func request(messageDic: Dictionary<String, String>) -> Promise<Any> {
    var dic:Dictionary<String,String> = messageDic as Dictionary
    dic.updateValue("system", forKey: "channel")
    let requestPromise = Promise<Any> { fulfill, reject in
        socket.emit(ScalaConfig.SOCKET_MESSAGE,dic)
        var promiseDic = Dictionary<String,Any>()
        promiseDic  = [ "fulfill": fulfill,"reject":reject]
    }
    return requestPromise
}
}