iOS Swift4 如何协调 T.Type 和类型(:) to pass dynamic class type as function parameter?

标签 ios generics swift4 typechecking type-safety

我正在尝试通过使用类类型字符串作为字典键来实现配置参数的通用存储。这个想法是检索函数将返回一个正确类型的对象。每种类型在存储中都是唯一的。但是,当我调用该函数时,出现 Swift 编译器错误并且不确定如何解释它:

Compiler Error: 
Cannot invoke 'retrieve' with an argument list of type '(type: Any.Type)

我检查了文档,似乎 type(of:) 方法应该返回运行时类,而编译器让它看起来像是在提示,因为它认为我正在传递一个任意类型

如何在不使用该类实例的情况下将 Swift 类名作为函数参数传递?

func retrieve<T>(type: T.Type) -> T? {

    let valueKey = String(describing: type)
    print("retrieving: \(valueKey)")
    return dictionary[valueKey] as? T
}
func update(with value: Any) {
    let valueKey = String(describing: type(of: value))
    print("Updating: \(valueKey)")
    dictionary[valueKey] = value
}

let testCases: [Any] = [1, 2.0, "text"]

for testCase in testCases {
    subject.update(with: testCase)
    //Compiler Error: Cannot invoke 'retrieve' with an argument list of type '(type: Any.Type)
    let t = type(of: testCase)
    let retrieved = subject.retrieve(type: t)
    //check for equality
}
//this works
expect(subject.retrieve(type: Int.self)).to(equal(1))
expect(subject.retrieve(type: Double.self)).to(equal(2.0))
expect(subject.retrieve(type: String.self)).to(equal("text"))

我做了更多测试,发现我的数组似乎不支持 type(of: ) documentation,此函数返回与“Any”相同的对象:

func retrieve<T>(sample: T) -> T? {

    let valueKey = String(describing: type(of: sample))
    print("retrieving: \(valueKey)") //always retrieves same object "Any"
    return dictionary[valueKey] as? T
}

更新:感谢您的回复,以澄清 - 测试用例旨在从简单类型开始,然后发展到更复杂的类。实际实现将存储自定义类型的完全唯一实例,而不是字符串或整数。

let testCases: [Any] = [ConnectionConfig(...),
                                    AccountID("testID"),
                                    AccountName("testName")]

测试识别检索函数的通用性质并分配适当的类型,代码完成证明了这一点:

    expect(subject.retrieve(type: ConnectionConfig.self)?.ip).to(equal("defaultIP"))
    expect(subject.retrieve(type: AccountID.self)?.value).to(equal("testId"))

RxSwift 上下文中的预期最终用途:为类提供通用存储并允许它为配置参数提取适当的值。如果不存在任何值,则会抛出错误并由单独的错误处理程序处理:

class RxConfigConsumer: ConfigConsumer {
    var connection: ConnectionConfig?
    var accountID: AccountID?

    init(with provider: ConfigProvider) {
        connection = provider.retrieve(type: ConnectionConfig.self)
        accountID = provider.retrieve(type: AccountID.self)
        //etc
    }

}

最佳答案

泛型与元类型 (.Type) 的组合非常奇怪,可能就是让您感到困惑的原因。如果你摆脱了通用的东西,就会像你期望的那样工作:

func retrieve(_ T:Any.Type) {
    print(type(of:T))
}
let testCases: [Any] = [1, 2.0, "text"]
for testCase in testCases {
    retrieve(type(of:testCase))
}
// Int.Type, Double.Type, String.Type

如果你真的想要泛型,那么去掉 .Type 并像这样写:

func retrieve<T>(_ t:T) {
    print(type(of:t))
}
let testCases: [Any] = [1, 2.0, "text"]
for testCase in testCases {
    retrieve(type(of:testCase))
}
// Int.Type, Double.Type, String.Type

然而,即便如此,我还是不清楚传递元类型的意义何在。

关于iOS Swift4 如何协调 T.Type 和类型(:) to pass dynamic class type as function parameter?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52582963/

相关文章:

ios - 资源未复制到包

generics - ToString 为单位值抛出 NullReferenceException ()

generics - 设计通用 CRUD session Bean

swift - 无法使用 Swift 4 包管理器导入包

ios - (SWIFT 3) 创建父子托管对象上下文

ios - 我应该使用 Core Data 还是 Plain SqLite

ios - 我可以像在 Android 中一样通过 ID 获取 View 的实例吗?

java - Eclipse 自动完成 - 当只有二进制 jar 可用时它如何知道泛型?

ios - Swift 4 错误的日期和时间

ios - 快速引用数组的通用变量