【发布时间】:2020-12-19 19:11:36
【问题描述】:
我的问题是关于 Swift 中泛型的一个复杂用例。我会尽量解释清楚。
我的 iOS 聊天应用程序的用户可以发送不同类型的消息:文本、图像、gif、问题等。 保存这些消息的数据的类设计是:
- 一个“抽象”类
Message,包含所有类型的消息(日期、发件人等)的信息 -
Message的最终子类,例如保存每种消息类型的特定信息的 TextMessage 或 ImageMessage(ImageMessage 的文件名、TextMessage 的文本等)
当从服务器检索消息时,它有一个名为service 的 JSON 属性,我将其解码为Service 枚举的情况。每个Service 案例有(1)一个数据类,和(2)一个单元类。数据类用于存放正确的T:Message类,cell类由collectionView提示知道需要根据消息服务出列哪种类型的cell。这是我的Service 枚举:
public enum Service : String, CaseIterable
{
case CHAT = "CHAT"
case IMAGE = "IMAGE"
// ...
public func getSubclass() -> Message.Type {
switch(self){
case .TEXT : return TextMessage.self
case .IMAGE : return ImageMessage.self
// ...
}
}
/* problem here */
public func getCellClass <T> () -> MessageCollectionViewCell<T>.Type {
switch(self){
case .CHAT : return MessageCollectionViewCellChat.self
case .SENDING : return MessageCollectionViewCellChat.self
}
}
}
单元格的类设计是:
- 一个名为
MessageCollectionViewCell<T:Message>的抽象类创建实际的气泡视图,并在其下显示日期。在此类中声明了一个函数recycle,将被最终子单元格覆盖。 - 最终的子单元类:
MessageCollectionViewCellText、MessageCollectionViewCellImage等,MessageCollectionViewCell<T:Message>的子级。 T 需要是与单元格关联的数据类型。它们覆盖了方法 recycle(),因此每种类型的消息都可以以自己的方式回收(更改 TextMessages 的标签中的文本,更改 ImageView 中的位图为 ImageMessage..)
这是代码,所以更清楚:
class MessageCollectionViewCell<T:Message> : UICollectionViewCell {
// sub cells needs to override this identifier (used by the CollectionView to register cell)
class var cellIdentifier:String { return "MessageCollectionViewCell" }
init() {
// init chat bubble UI here..
}
public func recycle(withMessage: T) {
// UI actions to recycle the message that are common to all messages type ..
}
}
class MessageCollectionViewCellText : MessageCollectionViewCell<TextMessage>
{
override class var cellIdentifier:String { return "MessageCollectionViewCellText" }
let label = UILabel()
override init(frame:CGRect) {
super.init(frame:frame)
// create bubble content (put a label in the bubble, in this particular case of TextMessage)
}
override func recycle(message msgText: TextMessage){
// do all the things that are common to all message types (change date label for example)
super.setMessage(message: msg)
// specific things to do for TextMessage
label.text = msgText.text
}
}
问题是在服务枚举中返回单元类型的函数。在我的 Android 应用程序 (Java) 中,返回类型为:Class<? extends MessageCollectionViewCell<?>>。在这里,对于我在上面分享的 getCellClass 函数的代码,Swift 说 "Cannot convert return expression of type 'MessageCollectionViewCellText.Type' to return type 'MessageCollectionViewCell<T>.Type'"
我也试过这个:
// MT for Message Type, CT for Cell Type
public func getCellClass<MT:Message, CT:MessageCollectionViewCell<MT>> () -> CT.Type
{
switch(self) {
case .CHAT : return MessageCollectionViewCellChat.self as! CT.Type
case .IMAGE : return MessageCollectionViewCellImage.self as! CT.Type
}
}
它在没有警告的情况下正确编译,但应用程序崩溃,因为它无法转换为 CT.Type。有人有实现这个功能的想法吗?
感谢阅读
【问题讨论】:
-
Swift 不乐意在元类型中传输。在我看来,您的消息类型更像是一个枚举,其案例具有相关值。
-
是的,但即使有关联的值或函数返回一些东西,我也不知道我需要在这里存储/返回什么类型。类型 MessageCollectionViewCell
.Type 无法编译..
标签: swift generics uicollectionview