Я создаю объект сообщения с динамическим содержимым c. Мне удалось заставить это работать, но мое решение кажется склонным к ошибкам и имеет много шаблонного.
Внесение изменений, например: добавление нового динамического c типа контента или добавление удаления полей, по-видимому, требует много шагов.
Интересно, есть ли лучшее решение для моей проблемы?
Мое сообщение может выглядеть следующим образом:
{
"sentAt" : 1587022227,
"canBeDeletedForAllUsers" : true,
"content" : {
"memberUserIDs" : [
"7835BB24-2880-49E0-AEB1-8FEE74FE6569",
"478D6BDD-4921-4166-8ED2-9FB6194450E6",
"8D0B0684-EDE9-47C8-8318-D96BE91E0879"
]
},
"id" : "9D4A2D5E-F316-43D7-880E-D6793A11F9C8",
"senderUserID" : "71F1CDB9-D4D0-4C99-8B87-8E09A06259C8",
"channelID" : "group-241B1EED-3704-452D-8D9F-24F75E2AB76E",
"canBeDeletedOnlyForSelf" : true,
"canBeForwarded" : true,
"views" : 0,
"type" : "addMembers",
"canBeEdited" : true
}
ИЛИ
{
"sentAt" : 1587023808,
"canBeDeletedForAllUsers" : true,
"content" : {
"text" : "hello"
},
"id" : "3DA4810C-C6FF-456E-8431-A61674BF6967",
"senderUserID" : "30FD4396-CDD8-47BD-AD26-896F6F33AC9F",
"channelID" : "group-31EA8B8B-B39D-4B49-9D8C-F66D3E11A8F5",
"canBeDeletedOnlyForSelf" : true,
"canBeForwarded" : true,
"views" : 0,
"type" : "text",
"canBeEdited" : true
}
и может значительно отличаться в зависимости от того, какой контент я хочу добавить.
Это мое решение:
public enum MessageContentType: String, Codable {
case addMembers
case text
}
public protocol MessageContent {}
public struct Message: Encodable {
let id: String
let senderUserID: String
let channelID: String
let canBeEdited: Bool
let canBeForwarded: Bool
let canBeDeletedOnlyForSelf: Bool
let canBeDeletedForAllUsers: Bool
let views: Int
let content: MessageContent
var sentAt: Int64
var type: MessageContentType
enum CodingKeys: CodingKey {
case id
case senderUserID
case channelID
case canBeEdited
case canBeForwarded
case canBeDeletedOnlyForSelf
case canBeDeletedForAllUsers
case views
case content
case sentAt
case type
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(senderUserID, forKey: .senderUserID)
try container.encode(channelID, forKey: .channelID)
try container.encode(canBeEdited, forKey: .canBeEdited)
try container.encode(canBeForwarded, forKey: .canBeForwarded)
try container.encode(canBeDeletedOnlyForSelf, forKey: .canBeDeletedOnlyForSelf)
try container.encode(canBeDeletedForAllUsers, forKey: .canBeDeletedForAllUsers)
try container.encode(views, forKey: .views)
try container.encode(sentAt, forKey: .sentAt)
try container.encode(type, forKey: .type)
if let content = content as? MessageChatAddMembers {
try container.encode(content, forKey: .content)
} else if let content = content as? MessageText {
try container.encode(content, forKey: .content)
} else {
let context = DecodingError.Context(codingPath: encoder.codingPath, debugDescription: "Invalid content!")
throw DecodingError.dataCorrupted(context)
}
}
}
extension Message: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
senderUserID = try container.decode(String.self, forKey: .senderUserID)
channelID = try container.decode(String.self, forKey: .channelID)
canBeEdited = try container.decode(Bool.self, forKey: .canBeEdited)
canBeForwarded = try container.decode(Bool.self, forKey: .canBeForwarded)
canBeDeletedOnlyForSelf = try container.decode(Bool.self, forKey: .canBeDeletedOnlyForSelf)
canBeDeletedForAllUsers = try container.decode(Bool.self, forKey: .canBeDeletedForAllUsers)
views = try container.decode(Int.self, forKey: .views)
sentAt = try container.decode(Int64.self, forKey: .sentAt)
type = try container.decode(MessageContentType.self, forKey: .type)
switch type {
case .addMembers:
content = try container.decode(MessageChatAddMembers.self, forKey: .content)
case .text:
content = try container.decode(MessageText.self, forKey: .content)
}
}
}
public struct MessageChatAddMembers: Codable, MessageContent {
let memberUserIDs: [String]
init() {
memberUserIDs = [UUID().uuidString, UUID().uuidString, UUID().uuidString]
}
}
public struct MessageText: Codable, MessageContent {
let text: String
init() {
text = "hello"
}
}