В Swift, как вы можете проверить, реализует ли объект дополнительный метод протокола, который отличается сигнатурой, фактически не вызывая этот метод? - PullRequest
0 голосов
/ 24 сентября 2018

Используя Swift, возможно ли проверить, реализует ли объект необязательный метод протокола без фактического вызова этого метода?Это работает, за исключением случаев, когда дополнительные методы отличаются только своей сигнатурой.

Рассмотрите этот код ...

@objc public protocol TestDelegate : AnyObject {
    @objc optional func testx()
    @objc optional func test(with string:String)
    @objc optional func test(with2 int:Int)
}

let delegate:TestDelegate? = nil

if let _ = delegate?.test(with:) {
    print("supports 'test(with:)'")
}

if let _ = delegate?.testx {
    print("supports 'testx'")
}

Если вы вставите вышеперечисленное в игровую площадку, он будет работать как положено.

Однако, если вы измените testx на test, он больше не будет работать.

Аналогично, если вы измените test(with2) на test(with), то это тоже не сработает.

Есть ли способ проверить те методы, которые отличаются только сигнатурой?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Как также показано в Как разрешить «неоднозначное использование» ошибки компиляции с помощью синтаксиса Swift #selector? , вы можете явно привести ссылку на функцию к ее ожидаемому типу, чтобы устранить такие неоднозначности.

Единственное отличие состоит в том, что, поскольку такие ссылки на функции относятся к @optional требованиям протокола, предъявляемым через необязательную цепочку, вам необходимо привести к необязательному типу функции.Оттуда вы можете сделать сравнение с nil, чтобы определить, является ли оба делегата ненулевым, и он реализует данное требование.

Например:

import Foundation

@objc public protocol TestDelegate : AnyObject {
  @objc optional func test()

  // Need to ensure the requirements have different selectors.
  @objc(testWithString:) optional func test(with string: String)
  @objc(testWithInt:) optional func test(with int: Int)
}

class C : TestDelegate {
  func test() {}
  func test(with string: String) {}
  func test(with string: Int) {}
}

var delegate: TestDelegate? = C()

if delegate?.test as (() -> Void)? != nil {
  print("supports 'test'")
}

if delegate?.test(with:) as ((String) -> Void)? != nil {
  print("supports 'test w/ String'")
}

if delegate?.test(with:) as ((Int) -> Void)? != nil {
  print("supports 'test w/ Int'")
}

// supports 'test'
// supports 'test w/ String'
// supports 'test w/ Int'

Обратите внимание, что я дал уникальные селекторы требований test(with:), чтобы гарантировать, что они не конфликтуют (это не влияет на устранение неоднозначности, только позволяет классу C соответствовать TestDelegate).

0 голосов
/ 25 сентября 2018

Привет, MarqueIV для проверки дополнительной функции, которую вы можете использовать встроенной функцией

func отвечает (aSelector: Selector!) -> Bool

Возвращает логическое значение, которое указываетреализует ли получатель или наследует метод, который может ответить на указанное сообщение.

Приложение отвечает за определение того, следует ли считать ложный ответ ошибкой.

Вы не можете проверить, является ли объектнаследует метод от своего суперкласса, отправляя ответы (to :) объекту, используя ключевое слово super.

Этот метод все равно будет проверять объект в целом, а не только реализацию суперкласса.

Следовательно, отправка ответов (to :) на super равносильна отправке его себе.

Вместо этого вы должны вызывать метод класса NSObject instancesRespond (to :) непосредственно в суперклассе объекта, как показано в следующем фрагменте кода.

Листинг 1

if( [MySuperclass instancesRespondToSelector:@selector(aMethod)] ) {
    // invoke the inherited method
    [super aMethod];
}

Вы не можете просто использовать [[self superclass] instancesRespondToSelector: @selector (aMethod)], так как это может привести к сбою метода, если он вызывается подклассом.

Обратите внимание, что если получатель может пересылать aSelectorсообщения другому объекту, он сможет ответить на сообщение, хотя и косвенно, даже если этот метод возвращает false.Параметры
aSelector
Селектор, который идентифицирует сообщение.Возвращает true, если получатель реализует или наследует метод, который может ответить на aSelector, в противном случае - false.SDK iOS 2.0+, macOS 10.0+, tvOS 9.0+, watchOS 2.0 +

...