2015-10-28 2 views
2

Я хочу узнать, является ли точный экземпляр объекта в массиве. Это казалось очень полезной функцией, чтобы иметь, так что я пытался сделать расширение массива:Swift2: расширение для массива, которое сравнивает точные объекты?

extension Array { 
    func containsIdenticalObject(object: AnyObject)->Bool { 
    if self.count > 0 { 
     for (_, objectToCompare) in self.enumerate() { 
     if object === objectToCompare { 
      return true 
     } 
     } 
    } 
    return false 
    } 
} 

Я получаю сообщение:

error: binary operator '===' cannot be applied to operands of type 'AnyObject' and 'Element'. 

Я пытался перетасовываю его вокруг с различными родовыми изменениями, такие как <T: This> и where Self: That, но я всегда получаю то же сообщение.

Кажется, что это определенно возможно. Как мне изменить эту функцию, чтобы она работала?

Редактировать

Я был в состоянии сделать эту работу в качестве автономной функции:

func arrayContainsExactInstance<T>(array:[T], _ object:T)->Bool { 
    if array.count > 0 { 
    for (_, givenObject) in array.enumerate() { 
     let givenObjectAsAnyObject = givenObject as! AnyObject 
     let targetObjectAsAnyObject = object as! AnyObject 
     if ObjectIdentifier(givenObjectAsAnyObject) == ObjectIdentifier(targetObjectAsAnyObject) { 
      return true 
     } 
    } 
    } 
    return false 
} 

... который является большим, за исключением а) ​​кажется чрезмерно сложным, и б) должен быть какой-то способ, чтобы добавить его к фактическому расширению ...

ответ

3

«тождественный оператор» === определен для экземпляров классов , поэтому вы должны ограничить расширение массивами, в которых элементы также являются экземплярами класса.

AnyObject является протокол, к которому все классы неявно соответствовать, так что вы можете добавить where Element : AnyObject ограничение декларированию в расширения.

Обратите внимание, что сам метод можно упростить.

extension Array where Element : AnyObject { 
    func containsIdenticalObject(object: AnyObject) -> Bool { 
     return contains { $0 === object } 
    } 
} 

Пример:

class MyClass { } 

let a = MyClass() 
let b = MyClass() 
let c = MyClass() 
let array = [a, b] 

array.containsIdenticalObject(c) // false 
array.containsIdenticalObject(b) // true 

Обновление: К сожалению, - как вы наблюдали - это не работает, если тип элемента массива является протокол:

protocol MyProtocol: AnyObject {} 
class MyClass: MyProtocol {} 
let classInstance = MyClass() 
let classArray: [MyProtocol] = [classInstance] 
classArray.containsIdenticalObject(classInstance) 
// using 'MyProtocol' as a concrete type conforming to protocol 'AnyObject' is not supported 

Причина в том, что pr otocol не соответствует самому себе или протоколу , который он наследует (сравните Protocol doesn't conform to itself?). Та же проблема будет происходить с вашей свободной функцией , если ограничить тип T к типам классов вместо принудительно литейных элементов для AnyObject:

func arrayContainsExactInstance<T : AnyObject>(array:[T], _ object:T) -> Bool 

Я не знаю, как решить, что с текущим Swift 2,1 , но эта проблема не связана с тем, используете ли вы метод расширения или функцию .

Если вы готовы предположить что элементы являются экземплярами класса , то вы можете написать метод расширения как

extension Array { 
    func containsIdenticalObject(object: Element) -> Bool { 
     guard let obj = object as? AnyObject else { return false } 
     return contains { ($0 as? AnyObject) === obj } 
    } 
} 

что примерно то, что ваша функция делает (только с условным гипсе вместо принудительного броска). Но учтите, что это может привести к неожиданным результатам для неклассовых элементов, поскольку некоторые типы (например Int являются молча преобразуются в объекты (например, NSNumber), где это необходимо.

+0

ты испытал это в Playground? Это не бросаться сама ошибка, но когда я пытаюсь использовать ее с массивом пользовательского класса 'MyClass', например, я получаю сообщение:' error: using 'MyClass' как конкретный тип, соответствующий протоколу 'AnyObject' не поддерживается' –

+0

@LeMotJuiced: не удается воспроизвести, он работает как в скомпилированном проекте, так и на игровой площадке для меня. Я добавил свой тестовый код для ответа для вашего удобства. - Какую версию Xcode вы используете? –

+0

Попробуйте это на игровой площадке с вашим расширение как написано: 'protocol MyProtocol: class, AnyObject {} // newline class MyClass: MyProtocol {} // newline let classInstance = MyClass() // newline let classArray: [MyProtocol] = [] // newline classArray.containsIdenticalObject (classInstance) // newline '(извините промежуток, я не знаю, как правильно это сделать в Markdown в комментариях). –

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