Swift中Message结构体初始化出现'Variable used before initialized'错误
问题分析:Message结构体初始化时的未初始化变量错误
问题描述
我在开发应用的消息模块,为消息定义了Message结构体,其中chatPartnerId是一个计算属性,会根据消息是否由当前用户发送,返回接收方ID或发送方ID:
var toID: String var fromID: String var isFromCurrentUser = Bool() var chatPartnerId: String { return isFromCurrentUser ? toID : fromID }
但在第83行的init?(document: QueryDocumentSnapshot)初始化器中,收到错误提示:"Variable self.toID used before being initialized",完整代码如下:
struct Message: MessageType { var id: String? let sentDate: Date let sender: SenderType var image: UIImage? var downloadURL: URL? var content: String? var toID: String var fromID: String var isFromCurrentUser = Bool() var chatPartnerId: String { return isFromCurrentUser ? toID : fromID } var messageId: String { return id ?? UUID().uuidString } var kind: MessageKind { if let image = image { let mediaItem = ImageMediaItem(image: image) return .photo(mediaItem) } else { return .text(content ?? "") } } init(user: User, content: String, fromID: String, toID: String) { sender = Sender(senderId: user.uid!, displayName: user.name!) self.content = content self.fromID = fromID self.toID = toID sentDate = Date() id = nil } init(user: User, image: UIImage, fromID: String, toID: String) { sender = Sender(senderId: user.uid!, displayName: user.name!) self.image = image content = "" self.fromID = fromID self.toID = toID sentDate = Date() id = nil } init?(document: QueryDocumentSnapshot) { let data = document.data() guard let sentDate = data["created"] as? Timestamp, let senderId = data["senderId"] as? String, let fromID = data["fromID"] as? String, let toID = data["toID"] as? String, let senderName = data["senderName"] as? String else { return nil } id = document.documentID self.sentDate = sentDate.dateValue() sender = Sender(senderId: senderId, displayName: senderName) self.isFromCurrentUser = fromID == Auth.auth().currentUser?.uid if let content = data["content"] as? String { self.content = content downloadURL = nil } else if let urlString = data["url"] as? String, let url = URL(string: urlString) { downloadURL = url content = "" } else { return nil } } //THIS IS line 83 } // MARK: - DatabaseRepresentation extension Message: DatabaseRepresentation { var representation: [String: Any] { var rep: [String: Any] = [ "created": sentDate, "senderId": sender.senderId, "fromID": fromID, "toID": toID, "senderName": sender.displayName ] if let url = downloadURL { rep["url"] = url.absoluteString } else { rep["content"] = content } return rep } } // MARK: - Comparable extension Message: Comparable { static func == (lhs: Message, rhs: Message) -> Bool { return lhs.id == rhs.id } static func < (lhs: Message, rhs: Message) -> Bool { return lhs.sentDate < rhs.sentDate } }
原因分析
Swift对结构体初始化有严格规则:所有存储属性必须在初始化流程结束前完成赋值。
在你的init?(document:)初始化器中,虽然通过guard语句获取了fromID和toID的取值,但并没有将它们赋值给结构体的self.fromID和self.toID存储属性。当执行self.isFromCurrentUser = fromID == Auth.auth().currentUser?.uid时,Swift的初始化检查机制会预判后续可能访问chatPartnerId(该属性依赖toID和fromID),而此时这两个存储属性还未赋值,因此触发未初始化错误。
解决方案
在初始化器中,获取到fromID和toID后,立即将它们赋值给对应的存储属性,且要放在设置isFromCurrentUser之前。修改后的初始化器代码如下:
init?(document: QueryDocumentSnapshot) { let data = document.data() guard let sentDate = data["created"] as? Timestamp, let senderId = data["senderId"] as? String, let fromID = data["fromID"] as? String, let toID = data["toID"] as? String, let senderName = data["senderName"] as? String else { return nil } id = document.documentID self.sentDate = sentDate.dateValue() sender = Sender(senderId: senderId, displayName: senderName) // 先完成fromID和toID的赋值 self.fromID = fromID self.toID = toID self.isFromCurrentUser = fromID == Auth.auth().currentUser?.uid if let content = data["content"] as? String { self.content = content downloadURL = nil } else if let urlString = data["url"] as? String, let url = URL(string: urlString) { downloadURL = url content = "" } else { return nil } }
内容的提问来源于stack exchange,提问作者Vandal
相关产品推荐
相关产品推荐

