委托或数据源中的泛型

时间:2014-12-10 08:28:09

标签: ios generics swift protocols

我正在尝试在delegatedataSource协议中找到使用泛型的解决方案。

现在我宣布了以下protocol

@objc protocol PageViewControllerDelegate {
    optional func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController:UIViewController)
}

我想要的是这样的通用协议:

@objc protocol PageViewControllerDelegate {
    typealias T
    optional func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController:T)
}

这会导致以下问题:

  1. 当我宣布typealias时,我不能再使用@objc和可选标签

  2. 当我将协议声明为非泛型类的属性时,我得到错误“协议只能用作通用约束,因为它具有自我”

  3. 我已宣布该财产如下:

    class PageViewController: UIViewController, UIScrollViewDelegate {
        var delegate:PageViewControllerDelegate?
    }
    

    欢迎任何帮助。

    哦,我只是用这个PageViewController案例作为例子来判断这是否可行。我不是在寻找另一种使用UIPageViewController的方法。

1 个答案:

答案 0 :(得分:0)

首先,我相信您打算

protocol PageViewControllerDelegate {
    associatedtype T: UIViewController
    func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController: T)
}

尽管这是旧版本的Swift的旧线程,所以在协议中可能已经使用了typealias

看来,Objective-C不支持关联类型,因此无法同时提供可选协议实现和关联类型。但是,您可以利用协议要求有效地创建可选实现,该协议要求通过扩展名获得默认实现,如下所示:

protocol PageViewControllerDelegate {
    associatedtype T: UIViewController
    func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController: T)
}

extension PageViewControllerDelegate {
    // Does nothing on its own. Note that because this method is a requirement of the protocol, dynamic dispatch is used instead of static dispatch
    func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController: T) {}
}

class MyClass: PageViewControllerDelegate {
    typealias T = UIPageViewController

    // No compile-time errors for an effectively optional method

    // Custom implementation
    //func pageViewController(pageViewController: PageViewController, didScrollToViewController viewController: UIPageViewController) {
    //
    //}
}

由于声明不明确,因此不允许将变量声明为具有关联类型的协议的类型。这类似于在Swift中不允许简单地将变量声明为Array类型的方式类似:由于其通用参数,没有单一的Array类型。关联类型是通用类型的通用参数的协议等效项。有关其他协议功能的进一步说明,请参见here

您可以尝试以下方法

protocol PageViewControllerDelegate {
    associatedtype T: UIViewController
    func pageViewController(pageViewController: PageViewController<Self>, didScrollToViewController viewController: T)
}

extension PageViewControllerDelegate {
    func pageViewController(pageViewController: PageViewController<Self>, didScrollToViewController viewController: T) {}
}


class PageViewController<Delegate: PageViewControllerDelegate> : UIViewController, UIScrollViewDelegate {
    private var delegate: Delegate?
}

final class MyDelegate: PageViewControllerDelegate {
    typealias T = UIPageViewController

    func pageViewController(pageViewController: PageViewController<MyDelegate>, didScrollToViewController viewController: UIPageViewController) {
        // Do something
    }
}

唯一的缺点是必须在协议方法中使用final将委托标记为Self

这是一个旧线程,到目前为止,您可能已经很清楚这些功能。希望无论如何都会有帮助。