У меня есть класс ChatsocketIO, который обрабатывает все функции SocketIO, связанные с функциями чата в приложении. Скелет этого класса выглядит так, как показано ниже.

Мой вопрос: когда Socket получает сообщение, он запускает "socket! .On (" msg ")", однако я не понимаю, как передать это обратно в класс контроллера представления, который я вызываю этот класс API. Я также добавил класс View Controller ниже.

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;
    }
    
}

В моем контроллере представления у меня есть что-то вроде того, что показано ниже, я хочу передать ChatSocketAPI "self.items" вызывающему ниже контроллеру, когда приходит сообщение, я не понимаю, как это сделать?

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
    }
0
mahen3d 6 Окт 2021 в 13:12

2 ответа

Лучший ответ

Сделайте свой MessagingViewController слушателем для ChatServiceAPI. Вы можете реализовать это так:

Создайте протокол, подобный следующему:

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

И сделайте так, чтобы ваш контроллер соответствовал ему:

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

Затем в ChatServiceAPI вы можете создать переменную с именем listeners:

private var listeners: [MessageListener] = []

И методы добавления и удаления слушателей:

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

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

Что касается последней части, в вашем ChatServiceAPI, когда получено событие «msg», вам необходимо отправить сообщение всем вашим зарегистрированным слушателям. Итак, примерно так:

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

Теперь вам также нужно зарегистрировать свой viewController в качестве слушателя. Итак, вы должны позвонить ChatServiceAPI.shared.add(listener: self) в свой viewDidLoad. Не забудьте также вызвать ChatServiceAPI.shared.remove(listener: self), чтобы предотвратить утечку памяти.

1
marosoaie 6 Окт 2021 в 10:56

Вы можете вернуть данные в контроллер представления, написав socket.ON внутри функции с экранирующим блоком.

Вот мой пример кода, который я использую

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("")
            }
        }
    }

Затем вы можете вызвать эту функцию getResponse в viewDidLoad внутри вашего viewController. Нравится -

self.socketInstance.getResponse { socketResponse in
     // socketResponse is the response
     // this will execute when you get new response from socket.ON
}
0
Imran0001 6 Окт 2021 в 10:34