Home > Blockchain >  SWIFT How to Send Data back to the ViewController from a SocketAPI Class?
SWIFT How to Send Data back to the ViewController from a SocketAPI Class?

Time:10-06

I have ChatsocketIO class which handles all the SocketIO functions related to the chat functionality of the app. The skeleton of that class looks like below.

My Question is when the Socket receives a message it fires the "socket!.on("msg")", However i am confused how to pass this back to the view controller class which i am calling this API class. I have added the View Controller class as well below..

class ChatServiceAPI {
    // MARK: - Properties
    var manager: SocketManager? = nil
    var socket: SocketIOClient? = nil
    
    //Chat Variables
    var items:[Message] = []
    
    // MARK: - Life Cycle
    init() {
        setupSocket()
        setupSocketEvents()
        socket?.connect()
    }
    
    static let shared = ChatServiceAPI();
    
    func stop() {
        socket?.removeAllHandlers()
    }
    
    // MARK: - Socket Setup
    func setupSocket() {
        socket = manager!.defaultSocket;
    }
    
    func setupSocketEvents() {
        
        
        if socket!.status != .connected{
            socket!.connect()
        }
        
        socket!.on(clientEvent: .connect) { (data, emitter) in
            print("==connecting==");
        }
       
      
        socket!.on("msg") { (data, emitter) in
            
            let mesage = Message()
            let jsonObject = JSON(data[0])
            let messageString: String? = jsonObject["msg"].string
            let userIDFrom: Int? = jsonObject["profile"]["id"].int
            
            if(userIDFrom != Int(self.userIDTo)) {
                return
            }
            if( userIDFrom == nil)
            {
                return
            }
            
            mesage.data = JSON(["from_user": self.userIDTo, "to_user": self.userID, "msg": self.convertStringToHtmlCode(msg: messageString ?? ""), "created": Date().description(with: .current)])
            
            self.items.insert(mesage, at: 0)

            //self.viewMessagesList.reload(messages: self.items, conversation: self.conversation)
        }
        
        
        
        
        socket!.on("disconnect") { (data, emitter) in
            print("===disconnect==");
            self.isConnected = false
        }
        
        socket!.connect();
        
    }
    
    // MARK: - Socket Emits
    func register(user: String) {
        socket?.emit("add user", user)
    }
    
    func send(message: String, toUser: String) {
        let data = NSMutableDictionary()
        data.setValue(message, forKey: "msg")
        data.setValue(toUser.lowercased(), forKey: "to")
        socket!.emit("send", data);
        return;
    }
    
}

In My View Controller, I have something like below, I want to pass ChatSocketAPI's "self.items" to the below-calling controller, when a msg comes, I am confused about how to do this?

import UIKit
import SocketIO
import SwiftyJSON
import EZAlertController

class MessagingViewController: UIViewController {
    let viewMessagesList = MessagesListViewController()
    let bottomMenuChatView = BottomMenuChatView(frame: CGRect.zero)
    var isAnimation = false
    let emojiView = EmojiView(frame: CGRect.zero)
    
    func setupSocketIO() {
        
        ChatServiceAPI.init();
        self.socket = ChatServiceAPI.shared.socket;
    }

override func viewDidLoad() {
        super.viewDidLoad()

        self.setupSocketIO()
        ChatServiceAPI.shared.page = 0;
        ChatServiceAPI.shared.items = []    
}

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.setupNavigation()
        
        if Reachability.isConnectedToNetwork() == false {
            EZAlertController.alert("", message: "Please check your internet connection")
            return
        }
        
        // bottom menu setup
        bottomMenuChatView.btnSendMessage.addTarget(self, action: #selector(tappedBtnSendMessage(btn:)), for: .touchUpInside)
        bottomMenuChatView.btnEmoji.addTarget(self, action: #selector(tappedBtnEmoji(btn:)), for: .touchUpInside)
        bottomMenuChatView.textFieldMessage.delegate = self
    }

CodePudding user response:

You can back data to your view controller by writing socket.ON inside a function that have escaping block.

Here is my sample code that I use

func getResponse(completion: @escaping(_ resMessage: String) -> Void) {
        guard let socket = manager?.defaultSocket else {
            return
        }
        socket.on(myEventName) { (dataArray, socketAck) -> Void in
            
            guard let data = UIApplication.jsonData(from: dataArray[0]) else {
                return
            }

            do {
                let responseMsg = try JSONDecoder().decode(String.self, from: data)
                completion(responseMsg)
                
            } catch let error {
                print("Something happen wrong here...\(error)")
                completion("")
            }
        }
    }

Then you can call this function getResponse in viewDidLoad inside your viewController. Like this -

self.socketInstance.getResponse { socketResponse in
     // socketResponse is the response
     // this will execute when you get new response from socket.ON
}

CodePudding user response:

Make your MessagingViewController a listener for the ChatServiceAPI. You can implement that like this:

Create a protocol like the following:

protocol MessageListener: AnyObject {
    func messageReceived(text: String)
}

and make you controller conform to it:

extension MessagingViewController: MessageListener {
    func messageReceived(text: String) {
        // do whatever you need with the message
    }
}

Then, in the ChatServiceAPI you can create a var named listeners:

private var listeners: [MessageListener] = []

and methods for adding and removing listeners:

func add(listener: MessageListener) {
    self.listeners.append(listener)
}

func remove(listener: MessageListener) {
    self.listeners.remove(listener)
}

For the last part, in your ChatServiceAPI, when the "msg" event is received, you need to send the message to all of your registered listeners. So, something like this:

socket!.on("msg") { (data, emitter) in
    ...
    for listener in self.listeners {
        listener.messageReceived(text: ...)
    }
}

Now you also need to register your viewController as a listener. So you would call ChatServiceAPI.shared.add(listener: self) in your viewDidLoad. Don't forget to also call ChatServiceAPI.shared.remove(listener: self) to prevent memory leaks.

  • Related