MultipeerConnectivity MCPeerID 不符合 Codable

Posted

技术标签:

【中文标题】MultipeerConnectivity MCPeerID 不符合 Codable【英文标题】:MultipeerConnectivity MCPeerID does not conform to Codable 【发布时间】:2018-06-06 12:51:18 【问题描述】:

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

这在两个对等点具有相同名称的情况下可能会出现问题。而且我对每次发送都执行搜索也不满意。所以我试图在我的模型中直接使用 MCPeerIDs。但是,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 属性的帮助将不胜感激。

【问题讨论】:

这个你搞定了吗? 【参考方案1】:

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

1. 识别用户(业务层面),

对等点名称 M​​CPeerID(displayName: ) 不是对等点标识符,它只是针对人类观众(例如聊天室用户)。下面的第 3) 点显示了一种方式,即对等方在宣传其存在时如何包含其他用户信息。

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

框架 (MC) 会为您创建一个唯一的对等 ID,并建议在应用启动时重复使用(即持久化和重新加载)应用 (MCPeerID - official docs - example objetive-c using NSUserDefaults storage api)。

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

在你的模型中,你正在序列化任务,很好(虽然没有提到什么格式,.xml、.plist、.json 等),但我不明白你为什么要序列化这些 MCPeerID? 连接中的每个对等点都应该重新使用自己的 peerID,并且,如果他们希望向潜在的对等点宣传额外的信息,他们可以提供一个字典,其中包含有关对等点对象背后的业务用户的信息,例如:

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

(MCNearbyServiceAdvertiser docs)。

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

我会将框架 (MC) 从业务模型 (Task, User ...) 中分离出来,如下所示:

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

【讨论】:

以上是关于MultipeerConnectivity MCPeerID 不符合 Codable的主要内容,如果未能解决你的问题,请参考以下文章

iOS 和 Windows 之间的 MultipeerConnectivity

如何创建用于 MultiPeerConnectivity 的 SecIdentityRef?

MultipeerConnectivity 拒绝连接

MultipeerConnectivity 会话管理

Swift - MultipeerConnectivity 类型不符合协议

MultiPeerConnectivity 以编程方式