自定义协议
import Foundation
import Starscream
protocol HXWebSocketDelegate:AnyObject {
// TODO: Receive
func fetchReceiveEvent(_ content:@escaping(_ event: WebSocketEvent,_ client: WebSocketClient) -> Void)
func fetchDidReceiveData(_ content:@escaping(_ socket: WebSocketClient,_ data: Data) -> Void)
func fetchDidReceiveMessage(_ content:@escaping(_ socket: WebSocketClient,_ text: String) -> Void)
// TODO: Option
func fetchDidConnect(_ content:@escaping(_ socket: WebSocketClient) -> Void)
func fetchDidDisconnect(_ content:@escaping(_ socket: WebSocketClient,_ error: Error?) -> Void)
// TODO: Test
func fetchDidScrollToPositionFinish(_ content:@escaping(Int) -> Void)
}
创建 sm
class sm {
var hxWebsocket:WebSocket? = nil
weak var ws_delegate:HXWebSocketDelegate? = nil
// TODO: 闭包
private var closureReceiveEvent:((WebSocketEvent,WebSocketClient) -> Void)? = nil
private var closureDidReceiveMessage:((WebSocketClient,String) -> Void)? = nil
private var closureReceiveData:((WebSocketClient,Data) -> Void)? = nil
private var closureDidConnect:((WebSocketClient) -> Void)? = nil
private var closureDidDisconnect:(socket:WebSocketClient,error:Error?)? = nil
private var closureScrollToPosition:((Int) -> Void)? = nil
private init() {}
// TODO: 单例
static let pro = sm()
// TODO: connect
func connectServer(_ websoc:WebSocket? = nil,_ delegateTarget:WebSocketDelegate) {
if let webs = websoc {
self.hxWebsocket = webs
webs.delegate = delegateTarget
webs.connect()
}
else {
if let url = URL(string: "http://localhost:8080"){
let request = URLRequest(url: url)
self.hxWebsocket = WebSocket(request: request)
self.hxWebsocket?.delegate = delegateTarget
self.hxWebsocket?.connect()
}
}
}
/** SSL Pinning is also supported in Starscream.
var request = URLRequest(url: URL(string: "ws://localhost:8080/")!)
let pinner = FoundationSecurity(allowSelfSigned: true) // don't validate SSL certificates
let socket = WebSocket(request: request, certPinner: pinner)
var request = URLRequest(url: URL(string: "ws://localhost:8080/")!)
let compression = WSCompression()
let socket = WebSocket(request: request, compressionHandler: compression)
socket = WebSocket(url: URL(string: "ws://localhost:8080/")!, protocols: ["chat","superchat"])
//create a custom queue
socket.callbackQueue = DispatchQueue(label: "com.vluxe.starscream.myapp")
*/
// TODO: reconnect
func reconnectServer(_ URLStr:String,_ delegateTarget:WebSocketDelegate){
if let url = URL(string: URLStr),self.hxWebsocket == nil{
let request = URLRequest(url: url)
hxWebsocket = WebSocket(request: request)
hxWebsocket?.delegate = delegateTarget
hxWebsocket?.connect()
}
}
// TODO: write(string: "Hi Server!")
func writeOnText(_ text:String? = nil) {
if let msgText = text {
self.hxWebsocket?.write(string: msgText)
}
}
func writeOnData(_ data:Data? = nil) {
if let msgData = data {
self.hxWebsocket?.write(data: msgData)
}
}
// TODO: write(ping)
func writeOnPing(){
self.hxWebsocket?.write(ping: Data())
}
// TODO: write(pong)
func writeOnPong(){
self.hxWebsocket?.write(pong: Data())
}
// TODO: disconnect
func dismissConnect(){
self.hxWebsocket?.disconnect()
}
}
遵循协议
extension sm:WebSocketDelegate,HXWebSocketDelegate {
// 这个方法非代理方法
func didScrollToPosition(_ point:Int){
self.closureScrollToPosition?(point)
}
func didReceive(event: WebSocketEvent, client: WebSocketClient) {
self.closureReceiveEvent?(event,client)
}
func websocketDidConnect(socket: WebSocketClient) {
self.closureDidConnect?(socket)
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
self.closureDidDisconnect?(socket,error)
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
self.closureReceiveData?(socket, data)
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
self.closureDidReceiveMessage?(socket,text)
}
func fetchReceiveEvent(_ content: @escaping (_ e:WebSocketEvent, _ w:WebSocketClient) -> Void) {
if closureReceiveEvent == nil {
closureReceiveEvent = { event,client in
content(event, client)
}
}
}
func fetchDidReceiveData(_ content: @escaping (_ w:WebSocketClient,_ data:Data) -> Void) {
if closureReceiveData == nil {
closureReceiveData = { socket,data in
content(socket, data)
}
}
}
func fetchDidReceiveMessage(_ content: @escaping (_ w:WebSocketClient,_ text:String) -> Void) {
if closureDidReceiveMessage == nil {
closureDidReceiveMessage = {socket,message in
content(socket, message)
}
}
}
func fetchDidConnect(_ content: @escaping (_ w:WebSocketClient) -> Void) {
if closureDidConnect == nil {
closureDidConnect = { socket in
content(socket)
}
}
}
func fetchDidDisconnect(_ content: @escaping (_ w:WebSocketClient, Error?) -> Void) {
if closureDidDisconnect == nil {
closureDidDisconnect = { socket,error in
content(socket,error)
}
}
}
func fetchDidScrollToPositionFinish(_ content:@escaping(Int) -> Void) {
// 这里只在创建闭包之前打印一次(once)
print(closureScrollToPosition.debugDescription)
if closureScrollToPosition == nil {
closureScrollToPosition = { value in
content(value)
}
}
}
}
使用
class Usage {
var isConnected:Bool = false
func dispatchToUsage(){
sm.pro.fetchDidScrollToPositionFinish { value in
print(value)
}
}
func fetchUsage(){
//unowned 使用闭包前self不能为nil,也就是说Usage对象不能被释放,很适合SWIFTUI
sm.pro.fetchReceiveEvent { [unowned self] e, w in
switch e {
case .connected(let headers):
isConnected = true
print("websocket is connected: \(headers)")
case .disconnected(let reason, let code):
isConnected = false
print("websocket is disconnected: \(reason) with code: \(code)")
case .text(let string):
print("Received text: \(string)")
case .binary(let data):
print("Received data: \(data.count)")
case .ping(_):
break
case .pong(_):
break
case .viabilityChanged(_):
break
case .reconnectSuggested(_):
break
case .cancelled:
isConnected = false
case .error(let error):
debugPrint(error.debugDescription)
isConnected = false
case .peerClosed:
break
}
}
// 接收文本
sm.pro.fetchDidReceiveMessage { w, text in
}
// 接收数据
sm.pro.fetchDidReceiveData { w, data in
}
// 接收模块必须在连接模块之前
sm.pro.connectServer(sm.pro.hxWebsocket, sm.pro)
// 发送数据
sm.pro.writeOnPing()
//发送一个pong控制帧,Starscream会自动响应传入的ping 控制帧,这样你就不需要手动发送 pong
sm.pro.writeOnPong()
sm.pro.writeOnText("Hong")
sm.pro.writeOnData("Hong".data(using: .utf8))
// 禁用 respondToPingWithPong 来关闭自动 ping 响应。
sm.pro.hxWebsocket?.respondToPingWithPong = false
}
}
- 调用 (通过button模拟websocket代理发方法)
private unowned var pro = sm.pro
var body: some View {
VStack {
Text(" OK ")
.foregroundColor(.black)
.font(.title2)
Button.init("O K") {
// 3.button模拟循环调用
pro.didScrollToPosition(999)
}.font(.title)
.foregroundColor(.blue)
}
// 1.添加回调
let _ = Usage().dispatchToUsage()
// 2.模拟调用代理方法
let _ = pro.didScrollToPosition(666)
}