【问题标题】:Swift equivalent for java return type : Class<? extends MyClass<?>>java返回类型的Swift等价物:Class<?扩展 MyClass<?>>
【发布时间】:2020-12-19 19:11:36
【问题描述】:

我的问题是关于 Swift 中泛型的一个复杂用例。我会尽量解释清楚。

我的 iOS 聊天应用程序的用户可以发送不同类型的消息:文本、图像、gif、问题等。 保存这些消息的数据的类设计是:

  • 一个“抽象”类Message,包含所有类型的消息(日期、发件人等)的信息
  • Message 的最终子类,例如保存每种消息类型的特定信息的 TextMessage 或 ImageMes​​sage(ImageMes​​sage 的文件名、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&lt;T:Message&gt; 的抽象类创建实际的气泡视图,并在其下显示日期。在此类中声明了一个函数recycle,将被最终子单元格覆盖。
  • 最终的子单元类:MessageCollectionViewCellTextMessageCollectionViewCellImage 等,MessageCollectionViewCell&lt;T:Message&gt; 的子级。 T 需要是与单元格关联的数据类型。它们覆盖了方法 recycle(),因此每种类型的消息都可以以自己的方式回收(更改 TextMessages 的标签中的文本,更改 ImageView 中的位图为 ImageMes​​sage..)

这是代码,所以更清楚:

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&lt;? extends MessageCollectionViewCell&lt;?&gt;&gt;。在这里,对于我在上面分享的 getCellClass 函数的代码,Swift 说 "Cannot convert return expression of type 'MessageCollectionViewCellText.Type' to return type 'MessageCollectionViewCell&lt;T&gt;.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


【解决方案1】:

可能的解决方案不是使用类型,而是使用协议,然后可以避免代码中出现泛型类型不匹配问题,例如(有一些复制)

public protocol Message {}
public struct TextMessage: Message {}
public struct ImageMessage: Message {}

public protocol MessageCollectionViewCell {}
public class MessageCollectionViewCellChat: MessageCollectionViewCell {}

public enum Service : String, CaseIterable
{
    case CHAT = "CHAT"
    case IMAGE = "IMAGE"
    // ...
    

    public func getMessage() -> Message {
        switch(self){
            case .CHAT : return TextMessage()
            case .IMAGE : return ImageMessage()
            // ...
        }
    }
    
    /* problem here */
    public func getCell() -> MessageCollectionViewCell {
        switch(self){
            case .CHAT : return MessageCollectionViewCellChat()
            case .IMAGE : return MessageCollectionViewCellChat()
      
        }
    }
}

【讨论】:

  • 感谢您的回答,我会试一试。我猜 Swift 没有提供如此复杂的元类型处理?
猜你喜欢
  • 2013-10-18
  • 2019-07-17
  • 1970-01-01
  • 2017-07-02
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 1970-01-01
  • 2019-04-10
相关资源
最近更新 更多