【问题标题】:Error: Generic parameter 'T' could not be inferred.错误:无法推断通用参数“T”。
【发布时间】:2017-01-02 02:37:38
【问题描述】:

调用这个方法有问题:

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)
}

我收到错误消息:无法推断通用参数“T”。我确实理解错误的含义,但我不知道如何正确实现此调用。另外我有这个包装器的原因是我想将func setUpFeedbackForm 暴露给 obj-c 代码,并且由于 swift 的泛型,我不能直接将它导入到 obj-c。

你能告诉我正确的叫法吗?

【问题讨论】:

  • 你能解释一下为什么你在这里使用泛型吗?

标签: swift generics


【解决方案1】:

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

  • 继承自UIViewController
  • 符合FeedbackFormDelegate

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

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

因此,Objective-C 中的有效 UIViewController&lt;FeedbackFormDelegate&gt; 构造在 Swift 中没有直接等价物。

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

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 编程的角度考虑,那么这个解决方法遵循接口隔离原则,因为我们收到一个用于视图控制器的参数,另一个用于代理的参数,即使它们指向同一个对象后面。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 2019-06-10
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多