2017-01-02 3 views
3

У меня есть проблема с вызовом этого метода:Ошибка: общий параметр T не может быть выведен.

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

я получаю сообщение об ошибке: Generic параметр 'T' не может быть выведена. Я понимаю, что означает ошибка, но я не знаю, как правильно реализовать этот вызов. Также причина, по которой у меня есть эта оболочка, заключается в том, что я хочу показать func setUpFeedbackForm в код obj-c, и я не могу импортировать его непосредственно в obj-c из-за генериков Swift.

Не могли бы вы показать мне правильный способ его называть?

+2

Можете ли вы объяснить, почему вы вообще используете общий? – matt

ответ

1

У вас есть два ограничения на параметр viewController, которые должны быть удовлетворены при вызове setUpFeedbackForm:

  • наследство от UIViewController
  • соответствие с FeedbackFormDelegate

и setUpFeedbackFormWrapper удовлетворяет только один, таким образом, компилятор не знает, что делать с другим.

Проблема связана с ограничением Swift, которое не может напрямую выражать переменные/параметры, которые удовлетворяют как наследованию классов, так и протоколу, за исключением использования дженериков, что нарушает совместимость Objective-C.

Таким образом, действующая конструкция UIViewController<FeedbackFormDelegate> в Objective-C не имеет прямого эквивалента в Swift.

Обходной путь к этому ограничению заключается в объявлении третьего метода, который предоставляет аргументы согласования класса и протокола в виде двух различных параметров и вызывает этот метод как из совместимого 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 программирования, то этот способ следует интерфейс сегрегация принцип, мы получим один аргумент для материала контроллера представления, а другой для делегата вещи, даже если они указывают на тот же объект позади.

Смежные вопросы