我正在编写一个简单的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
}