-
swift尽可能多的使用struct而不是class,因为struct是按值传递,class是按照引用传递
-
所以在struct使用的时候需要多注意引用的保存。即便是class,也可能会存在引用的保存问题。
-
例子:
lass LztSocket: WebSocketDelegate {
private init() {}
// 唯一实例
public static var shared: LztSocket = .init()
// 初始化WebSocket,连接服务器,设置参数等。
func initSocket() {
if (socket != nil) {
return
}
let devId = LztContext.shared.deviceId;
let url = "\(LztConst.pushUrl)/wsapi/v1.0/ws/connect?token=\(LztContext.shared.pushToken)&dev_id=\(devId)&dev_type=ios";
var request = URLRequest(url: URL(string: url)!)
request.timeoutInterval = 5
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
let pinner = FoundationSecurity(allowSelfSigned: true) // don't validate SSL certificates
let socket = WebSocket(request: request, certPinner: pinner)
socket?.delegate = self
socket?.connect()
log.debug("初始化Socket连接完毕")
}
func didReceive(event: Starscream.WebSocketEvent, client: Starscream.WebSocket) {
log.debug("接收到服务器推送下来的消息了。")
}
}
-
查看以上代码,初看觉得没啥问题,运行起来,就是无法收取到任何服务器端消息。
-
仔细研究了一下,发现socket对象是在initSocket方法调用中产生的,没有意外的话,方法调用结束,它的生命周期也就结束了,会被回收掉。
-
因此,即便是有消息回来,也不可能有内容打印出来。虽然整个类是一个单例,创建之后,单例始终存在,但是因为没有任何引用到socket对象保存在单例的实例中,因此也会被回收掉。
-
解决方法:
// websocket 连接
private var socket:WebSocket? = nil;
-
在initialSocket方法中,把let去掉,这样,socket的生命周期就随着单例走了。只要单例不销毁,就可以一直接收到消息。
-
同样类似的问题,也会存在于SwiftUI的页面属性中。
-
因为SwiftUI的页面,全部是采用的struct XXXX:View 的形式,在构建页面的时候,如果是struct的属性,使用完毕之后,struct会被销毁,属性也会被销毁。虽然这时候页面还显示在画面中,但是已经不是你代码写的那个View了。
-
如果要让某个属性暂不销毁,就需要给他设置@State,或者其他可以保存状态的modifier。
评论区