После преобразования Swift 3 я не могу избавиться от ошибки: неоднозначное использование 'indexOfObject (passingTest :)'

Я использую indexesOfObjects(passingTest:) NSArray, но после того, как я преобразовал свой код в Swift 3, я получаю сообщение об ошибке: «Неоднозначное использование indexOfObject(passingTest:)». Мой код ниже отлично работал со Swift 2.3.

let indexesOfBubbleConstraints = bubbleConstraints.indexesOfObjects(passingTest: { (constraint, idx, stop) in
        if let view = constraint.firstItem as? UIView{
            return view.tag == usernameTag
        }
        else{
            return false
        }
    })

Для Swift 3 мне также пришлось преобразовать constraint в AnyObject, но это не решает реальной проблемы.

В итоге я использовал func indexesOfObjects(options: NSEnumerationOptions = [], passingTest: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) с пустым массивом для опций, как показано ниже. Это работает, но я до сих пор не понимаю, почему я получаю ошибку "Неоднозначно..." с моей исходной реализацией.

let indexesOfBubbleConstraints = bubbleConstraints.indexesOfObjects(options: [], passingTest: { (constraint, idx, stop) in
        if let view = (constraint as AnyObject).firstItem as? UIView{
            return view.tag == usernameTag
        }
        else{
            return false
        }
    })

person Stephan    schedule 19.09.2016    source источник


Ответы (1)


В Objective-C два метода indexesOf являются двумя разными методами:

- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))predicate NS_AVAILABLE(10_6, 4_0);
- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))predicate NS_AVAILABLE(10_6, 4_0);

И теперь Swift 3 импортирует их как неоднозначные два метода:

@available(iOS 4.0, *)
open func indexesOfObjects(passingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> IndexSet

@available(iOS 4.0, *)
open func indexesOfObjects(options opts: NSEnumerationOptions = [], passingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> IndexSet

Один indexesOfObjects(passingTest:), другой indexesOfObjects(options:passingTest:). И, к сожалению, Swift 3 дал значение по умолчанию для параметра options, что сделало простой вызов, такой как bubbleConstraints.indexesOfObjects(passingTest: ...), неоднозначным.

Это может быть вызов

  • indexesOfObjects(passingTest:)

or

  • indexesOfObjects(options:passingTest:) с присвоением значения по умолчанию options

(Swift не должен давать значение по умолчанию, если это вызывает подобную двусмысленность. Лучше отправить отчет об ошибке.)

В этом случае ваш обходной код с использованием indexesOfObjects(options:passingTest:) должен работать, но есть и другой обходной путь:

bubbleConstraints.indexesOfObjects(passingTest:) {constraint, idx, stop in
    //...
}

Ссылка на метод .indexesOfObjects(passingTest:) возвращает метод indexesOfObjects(passingTest:) в качестве замыкания, и приведенное выше выражение вызывает его.


Кстати, вам лучше рассмотреть возможность использования методов коллекции Swift, а не метода NSArrays:

let indexesOfBubbleConstraints = bubbleConstraints.enumerated().lazy
    .filter {(idx, constraint) in
        //...
    }.map{$0.offset}
person OOPer    schedule 19.09.2016
comment
Отличный подробный ответ! Я также ценю ваш последний комментарий и обязательно сделаю так, как вы рекомендуете. - person Stephan; 20.09.2016