2023.06.20 - [분류 전체보기] - Swift에서 socketIO 사용 방법 에서 설정한 SocketIOManager 파일을 이용한다.
1. SocketIOManager를 이용하여 소켓을 가져온다
2. 채팅방 아이디로 사용한 변수를 선언하고 메시지들을 표시할 테이블뷰와 입력창(텍스트뷰) 선언, 전체 메시지를 저장할 배열 선언
3. 가져온 소켓을 통해 이벤트 핸들러 등록
- 서버로부터 "receiveMessage" 이벤트가 발생하면 첫 번째 매개변수로 data를 받고 두 번째 매개변수로 응답 객체를 받는데 응답이 필요 없는 경우 _(언더 바)를 사용하여 응답을 사용하지 않는다
- 'data.first' 로 data의 첫 번째 요소를 가져오고 해당 요소를 '[String : Any]' 타입 (즉, ket, value) 타입으로 다운 캐스팅
- Message 구조체의 init을 이용하여 message 인스턴스를 생성
- message 구조체에서 'message'와 'isMyMessage' 키를 추출하여 초기화
- 생성된 message 인스턴스를 addMessageToChat 함수에 전달
4. 메시지를 채팅방에 추가하는 addMessageToChat() 함수
- message 타입으로 받아 message 타입의 배열 messages에 추가
- 테이블 뷰 reload
5. 메시지 전송 버튼 action
- 자신이 보낸 메시지와 상대 메시지를 구분하기 위해 Message 구조체의 isMyMessage 사용
- 자신이 보낸 메시지면 addMessageToChat() 함수로 채팅방에 추가 후 서버로 전송
- 서버로 보내는 데이터엔 roomId와 message 객체를 함께 "sendMessage" 이벤트로 전송
- 전송 이후 텍스트 필드 초기화
6. Message 구조체
- content : 메시지 내용
- isMyMessage : 자신이 보낸 메세지인지 여부 판단
- data 딕셔너리 형태로 받은 데이터는 "message', "isMyMessage" 키 값으로 값을 추출하여 content, isMyMessage에 저장
7. tableView 구현
- numberOfRowsInSection : 섹션에 표시할 행의 개수를 반환하는 메서드로 messages 배열의 개수만큼 행을 표시
- cellForRowAt : 주어진 indexPath에 해당하는 셀을 반환하는 메서드로 messages 배열에서 indexPath 번째 message를 가져오고 이 message의 isMyMessage 값을 확인하여 자신이 보낸 것인지 상대가 보낸 것인지를 구분함
- 구분한 cell에 따라 왼쪽 오른쪽으로 나뉘어져 있는 각각 다른 tableViewCell을 사용
전체 코드
//
// ViewController.swift
// PracticeSwift
//
// Created by 이수현 on 2023/06/20.
//
import UIKit
import SocketIO
class ChatViewController: UIViewController {
// 소켓 통신 관련 프로퍼티
let socketManager = SocketIOManager.shared
// 채팅방 아이디로 사용
var roomId: String = ""
// 메시지를 표시할 테이블뷰와 메시지 텍스트뷰
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var msgTextField: UITextField!
// 전체 메시지들을 저장할 배열
var messages: [Message] = []
override func viewDidLoad() {
super.viewDidLoad()
let myMsg = Message(content: "ㅎㅇㅎㅇ", isMyMessage: true)
let otherMsg = Message(content: "ㅎㅇㅎㅇㅎㅇ", isMyMessage: false)
addMessageToChat(myMsg)
addMessageToChat(otherMsg)
// 소켓 이벤트 핸들러 등록
socketManager.socket.on("receiveMessage") { [weak self] data, _ in
guard let messageData = data.first as? [String: Any],
let message = Message(data: messageData) else {
return
}
// 상대방이 보낸 메시지를 표시
self?.addMessageToChat(message)
}
}
// 메시지를 채팅방에 추가
func addMessageToChat(_ message: Message) {
messages.append(message)
tableView.reloadData()
}
// 메시지 전송 버튼 액션
@IBAction func sendMessage(_ sender: UIButton) {
guard let text = msgTextField.text else {
return
}
// 내가 보낸 메시지를 표시
let myMessage = Message(content: text, isMyMessage: true)
addMessageToChat(myMessage)
// 메시지 서버로 전송
let data: [String: Any] = ["roomId": roomId, "message": text]
socketManager.socket.emit("sendMessage", data)
// 메시지 입력 필드 초기화
msgTextField.text = ""
tableView.reloadData()
print(messages.count)
}
}
struct Message {
let content: String
let isMyMessage: Bool
init(content: String, isMyMessage: Bool) {
self.content = content
self.isMyMessage = isMyMessage
}
init?(data: [String: Any]) {
guard let content = data["message"] as? String,
let isMyMessage = data["isMyMessage"] as? Bool else {
return nil
}
self.content = content
self.isMyMessage = isMyMessage
}
}
extension ChatViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = messages[indexPath.row]
let cellIdentifier = message.isMyMessage ? "MyMessageCell" : "OtherMessageCell"
if (cellIdentifier == "MyMessageCell"){
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyMessageCell
cell.myMessageLabel.text = message.content
return cell
} else{
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! OtherMessageCell
cell.otherMessageLabel.text = message.content
return cell
}
}
// func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let message = messages[indexPath.row]
// let cellIdentifier = message.isMyMessage ? "MyMessageCell" : "OtherMessageCell"
// let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! TableViewCell
// cell.messageLabel.text = message.content
// return cell
// }
}
'Swift' 카테고리의 다른 글
Swift - UITableView 기초(1) (0) | 2023.06.27 |
---|---|
Swift 화면 전환 방식 3. Action Segue 방식 (0) | 2023.06.23 |
Swift 화면 전환 방식 2. 네비게이션 컨트롤러 + 소스(push) (0) | 2023.06.23 |
Swift - 동일 프로젝트 내 실행 storyboard 변경 (0) | 2023.06.22 |
Swift 화면 전환 방식 1. Present 방식 (0) | 2023.06.22 |