swift5学习之旅------简易聊天室
- 整体代码
Github还没上传,先用着Dropbox(可能要翻墙),看完有收获的感谢点个赞👍,如果翻不了墙要代码可以私聊我
https://www.dropbox.com/sh/5oyxgu8vwx0ypux/AAAJ_KACNiJXIdX77OT0srKUa?dl=0
聊天室使用了Golang中的通信,可以参考别人的介绍
https://github.com/dariencdd/StudyLog/wiki/Golang中client-server模型
golang通信
- 核心思想
- 网络层
要读取写入网络流数据,就要使用 CFReadStream,CFWriteStream
CFStreamCreatePairWithSocketToHost连接服务器
输入流:inputStream把硬盘文件中的数据,读取到内存中使用。对应的是readStream
输出流:outputStream把内存中的数据存到硬盘中,对应的是outputstream
//建立网络连接
func setupNetworkCommunication(){
//Unmanaged表示对不清晰的内存管理对象的封装
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, "127.0.0.1" as CFString, 98, &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
inputStream.delegate = self
inputStream.schedule(in: .current, forMode: .common)
outputStream.schedule(in: .current, forMode: .common)
inputStream.open()
outputStream.open()
}
输出流outputStream:加入聊天时,需要对username的值进行传递,所以需要把username输出到服务器,服务器再广播给所有使用者
发送信息也是输出流,把msg输出到服务器,再广播给所有使用者
outputStream.write(pointer, maxLength: data.count)
我们对username的判断可以知道服务器传送给自己的是否为自己发送的信息,再通过这个不同来改变UI
输入流inputStream:接收数据时,就是输入流,根据服务器接收到的数据对message的更改
//有字节输入
while stream.hasBytesAvailable {
let numberOfBytesRead = inputStream.read(buffer, maxLength: maxReadLength)
if numberOfBytesRead < 0, let error = stream.streamError {
print(error)
break
}
//构造消息对象
if let message = processedMessageString(buffer: buffer, length: numberOfBytesRead) {
// 通知
delegate?.received(message: message)
}
}
- UI层
因为msg信息不知道有多长,所以我们需要根据msg的信息对cell的高度进行更改
这是cell高度的判断
//静态方法确定高度
//message高度
static func height(for message: Message) -> CGFloat {
let maxSize = CGSize(width: 2*(UIScreen.main.bounds.size.width/3), height: CGFloat.greatestFiniteMagnitude)
let nameHeight = message.messageSender == .ourself ? 0 : (height(forText: message.senderUsername, fontSize: 10, maxSize: maxSize) + 4 )
let messageHeight = height(forText: message.message, fontSize: 17, maxSize: maxSize)
return nameHeight + messageHeight + 32 + 16
}
//文本的高度判断
private static func height(forText text: String, fontSize: CGFloat, maxSize: CGSize) -> CGFloat {
let font = UIFont(name: "Helvetica", size: fontSize)!
let attrString = NSAttributedString(string: text, attributes:[NSAttributedString.Key.font: font,NSAttributedString.Key.foregroundColor: UIColor.white])
let textHeight = attrString.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil).size.height
return textHeight
}
cell添加新信息时需要重新布局
func apply(message: Message) {
nameLabel.text = message.senderUsername
messageLabel.text = message.message
messageSender = message.messageSender
//需要重新布局
setNeedsLayout()
}
判断自己发的信息还是别人发的信息,发送者messageSender肯定是自己,所以直接为ourself
enum MessageSender {
case ourself
case someoneElse
}
var messageSender: MessageSender = .ourself
文本信息的判断
根据自己的名字来判断
let messageSender: MessageSender = (name == self.username) ? .ourself : .someoneElse
UI显示的不同
if messageSender == .ourself {
nameLabel.isHidden = true
messageLabel.center = CGPoint(x: bounds.size.width - messageLabel.bounds.size.width/2 - 16, y: bounds.size.height/2)
messageLabel.backgroundColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)
}
- 怎么使用
直接使用肯定是不行的,需要golang的编译
定位到server.go的文件夹,在终端运行