首页 > 解决方案 > 如何存储泛型类型以避免在 Swift 中需要它的内部结构?

问题描述

这个问题最好用一些代码来解释。

第1步

public struct Example<Content: View> {
    let content: () -> Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    
    func contentView() -> Content {
        self.content()
    }
}

第2步

现在当我添加一个内部结构时,编译器会抱怨不支持静态存储属性。

public struct Example<Content: View> {
    let content: () -> Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    
    func contentView() -> Content {
        self.content()
    }
    
    public struct ActionKey: Hashable, Equatable, RawRepresentable {
        public static let cancelButtonClicked = ActionKey("cancelButtonClicked") // Static stored properties not supported in generic types

        public static func == (lhs: ActionKey, rhs: ActionKey) -> Bool {
            return lhs.rawValue == rhs.rawValue
        }
        
        public let rawValue: String
        
        public init(rawValue: String) {
            self.rawValue = rawValue
        }
        
        public init(_ rawValue: String) {
            self.init(rawValue: rawValue)
        }
    }
}

第 3 步

为了消除错误,我们需要将其转换为计算变量。

public static var cancelButtonClicked: ActionKey { get { ActionKey("cancelButtonClicked") } }

问题

除了这已经很烦人之外,它变得更糟。我们还需要为一个完全不依赖它的结构提供一个通用参数。

_ = Example.ActionKey(rawValue: "cancelButtonClicked") // Generic parameter 'Content' could not be inferred

// Fix
_ = Example<AnyView>.ActionKey(rawValue: "cancelButtonClicked") 

如果我们能以某种方式避免将泛型类型放在外部作用域中,我们就可以避免它。但是,将类型存储在变量中不会让我使用它。所以我被困住了。有人有答案吗?

public struct Example<Content: View> {
    let content: Any
    let contentType: Any.Type
    
    init<Content>(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.contentType = Content.self
    }
    
    func contentView() -> ?? {
        self.content() // ??
    }
    
    public struct ActionKey: Hashable, Equatable, RawRepresentable {
        public static var cancelButtonClicked: ActionKey { get { ActionKey("cancelButtonClicked") } }

        public static func == (lhs: ActionKey, rhs: ActionKey) -> Bool {
            return lhs.rawValue == rhs.rawValue
        }
        
        public let rawValue: String
        
        public init(rawValue: String) {
            self.rawValue = rawValue
        }
        
        public init(_ rawValue: String) {
            self.init(rawValue: rawValue)
        }
    }
}

将内部结构置于其之外的唯一解决方案是什么?

标签: swiftgenericsswiftui

解决方案


这是可能的方法(但是我会把它放在外面,就像ButtonStyle在外面一样Button)......无论如何,它是:

public struct Example {
    private let content: AnyView

    init<Content: View>(@ViewBuilder content: @escaping () -> Content) {
        self.content = AnyView(content())
    }

    func contentView() -> some View {
        self.content
    }

    public struct ActionKey: Hashable, Equatable, RawRepresentable {
        public static let cancelButtonClicked = ActionKey("cancelButtonClicked") // Static stored properties not supported in generic types

        public static func == (lhs: ActionKey, rhs: ActionKey) -> Bool {
            return lhs.rawValue == rhs.rawValue
        }

        public let rawValue: String

        public init(rawValue: String) {
            self.rawValue = rawValue
        }

        public init(_ rawValue: String) {
            self.init(rawValue: rawValue)
        }
    }
}

推荐阅读