You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 16:06:28