通用协议方法 swift 无法将类型识别为类型

Generic protocol method swift can't recognise type as type

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

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

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

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

class MyClass {
    let a = "sometext"
}

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

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

然而这并不能编译!我收到一个错误 'Value of type MyClass has no member a'。所以我尝试将其转换为类型

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

这给出 'Force cast of MyClass to same type has no effect'。

出于某种原因,我发现这行得通:

typealias MyClassAlias = MyClass 

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

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

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

let selected = selectedItem as! MyClass

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

如果您使用类型别名,则可以在方法主体中使用它并进行编译,但是一旦 MyClass 泛型参数的实际类型更改为 MyClass class,转换将在运行时失败。

一般来说,您可能需要为每种类型的所选对象实现单独的委托协议。我假设视图控制器的通用参数 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)")
        }
    }