【问题标题】:Generic protocol method swift can't recognise type as type通用协议方法swift无法将类型识别为类型
【发布时间】:2017-03-08 10:31:14
【问题描述】:

我创建了一个通用视图控制器来从列表中选择一个项目,我想使用一个通用委托方法来返回已选择的项目。我的设置如下:

class ListPickerViewController<T>: UIViewController {
    var delegate: ListPickerViewControllerDelegate?
}

protocol ListPickerViewControllerDelegate {
    func listPickerViewControllerDelegate<T>(_ listPickerViewController: ListPickerViewController<T>, selectedItem: T)
}

我有一个对象列表,我将使用它来填充 ListPickerViewController

class MyClass {
    let a = "sometext"
}

在类中,我想从中获取所选项目,我实现该方法并为所选项目委托一个类型参数,用于列表中的对象类型。

func listPickerViewControllerDelegate<MyClass>(_ listPickerViewController: ListPickerViewController<MyClass>, selectedItem: MyClass) {
    print(selectedItem.a)
}

然而,这不会编译!我收到错误“MyClass 类型的值没有成员 a”。所以我尝试将其转换为类型

func listPickerViewControllerDelegate<MyClass>(_ listPickerViewController: ListPickerViewController<MyClass>, selectedItem: MyClass) {
    let selected = selectedItem as! MyClass
}

这使得“强制将 MyClass 强制转换为相同类型没有效果”。

出于某种原因,我发现这是可行的:

typealias MyClassAlias = MyClass 

func listPickerViewControllerDelegate<MyClass>(_ listPickerViewController: ListPickerViewController<MyClass>, selectedItem: MyClass) {
    let selected = selectedItem as MyClassAlias
    print(selected.a) // works
}

肯定有更好的方法吗?或者这是swift的缺点?

【问题讨论】:

    标签: swift generics swift3 polymorphism swift-protocols


    【解决方案1】:

    在你的协议实现中的委托方法的签名中MyClass只是一个通用参数,你可以使用TK等。它不一定有一个名为a的成员,因此第一个编译错误。在

    let selected = selectedItem as! MyClass
    

    它只是强制转换为自己的类型,几乎可以是任何类型。委托方法体中使用的MyClass 是函数签名中使用的泛型参数,而不是具有a 成员的MyClass 类。

    如果您使用 typealias,那么它可以在方法体中使用并且可以编译,但只要将 MyClass 泛型参数的实际类型更改为 MyClass 类以外的其他类型, cast 将在运行时失败。

    一般来说,您可能需要为每种类型的选定对象提供单独的委托协议实现。我假设视图控制器的通用参数T 是选定的对象类型。您还需要确保特定类型的视图控制器使用正确的委托实现。

    在 Swift 中,您可以使用关联类型来完成此操作。见https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html

    视图控制器和委托协议可能如下所示:

        class ListPickerViewController<T, D : ListPickerViewControllerDelegate>
        : UIViewController
        where D.T == T
        {
            var delegate: D?
        ......
        }
    
        protocol ListPickerViewControllerDelegate {
            associatedtype T
            func listPickerViewControllerDelegate<D>(_ controller: 
    ListPickerViewController<T, D>, selectedItem: T) where D.T == T
        }
    

    用于MyClass 类型的选定项的委托实现可能如下所示:

        class MyDelegateImpl : ListPickerViewControllerDelegate {
            typealias T = MyClass
    
            internal func listPickerViewControllerDelegate<D>(_ controller: 
    ListPickerViewController<MyClass, D>, selectedItem: MyClass) 
        where D.T == MyClass {
                print("In the delegate method!")
                print("MyClass.a = \(selectedItem.a)")
            }
        }
    

    【讨论】:

    • 对不起 - 我的意思是删除 WBSCode 并替换为 MyClass,现在更新
    • 为什么 MyClass 指的是 而不是实际的类的解释是有道理的。那么我们如何才能告诉 swift 这个方法应该是什么类型呢?或者 - 它总是属于泛型类型,由你决定吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 2022-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多