我正在编写一个简单的P2P聊天程序,到目前为止,我一直在模型中将MCPeerID的displayName属性存储为字符串,以确定向谁发送特定消息。在每个发送操作中,只要displayName匹配我模型中的字符串,我都会搜索connectedPeers数组并将MCPeerID复制到接收者列表中。

在两个对等方具有相同名称的情况下,这可能会出现问题。而且我也对每次发送都执行搜索感到不满意。因此,我尝试直接在模型中使用MCPeerID。但是,Xcode抱怨MCPeerID不符合Encodable或Decodable,因此我不确定如何解决此问题。

我的模型代表一个主题,该主题维护参与者列表以及谁在说什么的日志。因此,我可以在新参与者加入时同步他们,并在添加新消息时更新现有参与者。我的模型如下所示:

import Foundation
import MultipeerConnectivity


class Task : Codable {
    var uuidStr: String = UUID().uuidString
    var topic : String
    var history : [String] = []
    var users : [MCPeerID] = []

    ...

    private enum CodingKeys: String, CodingKey {
        case uuidStr
        case topic
        case history
        case users
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(uuidStr, forKey: .uuidStr)
        try container.encode(topic, forKey: .topic)
        try container.encode(history, forKey: .history)
        try container.encode(users, forKey: .users)
    }

    ...

}

(我没有显示标准的init(),因为这不是问题所在。)

在查看了文档之后,我看到了带有签名MCPeerID.init?(coder: NSCoder)func encode(with: NSCoder)的方法,但是我不确定如何指定NSCoder参数。任何有关如何序列化users属性的帮助将不胜感激。

最佳答案

这里似乎有一些问题(p2p是一个复杂的主题):

1.识别用户(业务级别),

对等方名称MCPeerID(displayName:)不是对等方标识符,它仅针对人类观看者(例如,聊天室用户)。下面的要点3)显示了对等方在宣传其他用户信息时如何包含其他用户信息的方法。

2.识别对等点(网络级别),

框架(MC)为您创建一个唯一的对等ID,并在应用程序启动(MCPeerID - official docs - example objetive-c using NSUserDefaults storage api)期间推荐该应用程序的重用(即持久和重新加载)。

3.共享对等 session 信息( session 级别)

在您的模型中,您正在对Task进行序列化,很好(尽管未提及哪种格式,.xml,.plist,.json等),但是我不明白为什么要对这些MCPeerID进行序列化?
连接中的每个对等方都应重用其自己的peerID,并且,可选地,如果他们希望向潜在对等方播发其他信息,则可以向字典提供有关对等对象背后的业务用户的信息,例如:

myAdvertiser = MCNearbyServiceAdvertiser(peer: reusableLocalPeerID, discoveryInfo: ["uuidStr" : "my-user-id-here"], serviceType: "my-tasks-app")

(MCNearbyServiceAdvertiser docs)。

4.分离关注点(数据级别)

我将框架(MC)与业务模型(任务,用户...)分开,如下所示:
class Task: Codable { var users: [User] ... }
class User: Codable { uid:String ...}
struct PeerRecord: { var peer:MCPeerID, var user_id:String, var name:String ... }
var foundPeers:[MCPeerID]
var connectedPeers:[String:PeerRecord] // e.g. ["a-user-id": PeerRecord(peer: ...)]

5.序列化

上面第2点的Apple示例显示了如何使用UserDefaults api序列化MCPeerID。

通常,当扩展Codable时,人们还希望在应用程序中的某处使用编码器(JSON,XML等),
将有问题的对象传递到此编码器的.encode(...)方法,例如:
func storeTasks(tasksCodable:[Task]) -> Bool {
  if let encoded_in_data_format = try? JSONEncoder().encode(tasksCodable) {
      UserDefaults.standard.set(encoded_in_data_format, forKey: "tasks")
      return true
  }
  return false
}

09-06 15:33