错误:通用参数' T'无法推断。

时间:2017-01-02 02:37:39

标签: swift generics

我在调用此方法时遇到问题:

func setUpFeedbackForm<T:UIViewController>(viewController: T,
                                        viewForScreenshot: UIView, 
                                        completionHandler: @escaping () -> ()) 
                                                  where T:FeedbackFormDelegate { ... }

在这个包装函数中:

public class func setUpFeedbackFormWrapper(viewController: UIViewController, 
                                        viewForScreenshot: UIView, 
                                        completionHandler: @escaping () -> ()) {

    setUpFeedbackForm(viewController: viewController,
                   viewForScreenshot: viewForScreenshot,
                   completionHandler: completionHandler)
}

我收到错误:通用参数&#39; T&#39;无法推断。我确实理解错误的含义,但我不知道如何正确实现此调用。我之所以拥有这个包装器,也是因为我希望将func setUpFeedbackForm公开给obj-c代码而且我不能直接将它导入到obj-c中,因为它的泛型。

你能告诉我正确的召唤方式吗?

1 个答案:

答案 0 :(得分:2)

调用viewController时,您需要满足setUpFeedbackForm参数的两个约束:

  • 继承UIViewController
  • 符合FeedbackFormDelegate

setUpFeedbackFormWrapper只满足一个,因此编译器不知道如何处理另一个。

问题是由Swift的限制引起的,Swift不能直接表示满足类继承和协议一致性的变量/参数,除非使用泛型,这会破坏Objective-C兼容性。

因此,UIViewController<FeedbackFormDelegate>中的有效Objective-C结构在Swift中没有直接等效结构。

此限制的解决方法是声明第3个方法,该方法将类继承和协议一致性参数公开为两个不同的参数,并从Objective-C兼容和Swift调用该方法 - 仅版本

func setUpFeedbackForm<T:UIViewController>(viewController: T,
                       viewForScreenshot: UIView,
                       completionHandler: @escaping () -> ())
    where T:FeedbackFormDelegate {
        setupFeedbackFormImpl(viewController: viewController,
                              feedbackFormDelegate: viewController,
                              viewForScreenshot: viewForScreenshot, completionHandler: completionHandler)
}

func setupFeedbackFormImpl(viewController: UIViewController,
                           feedbackFormDelegate: FeedbackFormDelegate,
                           viewForScreenshot: UIView,
                           completionHandler: @escaping () -> ()) {
    // actual code here
}

public func setUpFeedbackFormWrapper(viewController: UIViewController,
                                     viewForScreenshot: UIView,
                                     completionHandler: @escaping () -> ()) {

    guard let feedbackFormDelegate = viewController as? FeedbackFormDelegate else { 
        // you can also report errors here, if you want to
        // forbid runtime calls with controllers that are not FeedbackFormDelegate
        return 
    }
    setupFeedbackFormImpl(viewController: viewController,
                          feedbackFormDelegate: feedbackFormDelegate,
                          viewForScreenshot: viewForScreenshot,
                          completionHandler: completionHandler)
}

如果我们考虑SOLID编程,那么这个解决方法遵循接口隔离原则,因为我们收到一个视图控制器东西的参数,另一个参与委托的东西,即使他们指向同样的对象背后。