Я хочу создать класс, который может хранить объекты, соответствующие определенному протоколу. Объекты должны храниться в типизированном массиве. Согласно документации Swift протоколы могут использоваться как типы:
Поскольку это тип, вы можете использовать протокол во многих местах, где разрешены другие типы, включая:
- Как тип параметра или тип возвращаемого значения в функции, методе или инициализаторе
- Как тип константы, переменной или свойства
- Как тип элементов в массиве, словаре или другом контейнере
Однако следующее генерирует ошибки компилятора:
Протокол 'SomeProtocol' может использоваться только в качестве общего ограничения, поскольку он имеет Self или требования к связанному типу.
Как вы должны решить это:
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [SomeProtocol]()
func addElement(element: SomeProtocol) {
self.protocols.append(element)
}
func removeElement(element: SomeProtocol) {
if let index = find(self.protocols, element) {
self.protocols.removeAtIndex(index)
}
}
}
Ответы:
Вы столкнулись с вариантом проблемы с протоколами в Swift, для которой пока не найдено хорошего решения.
См. Также Расширение массива, чтобы проверить, отсортирован ли он в Swift? он содержит предложения о том, как обойти эту проблему, которая может подойти для вашей конкретной проблемы (ваш вопрос очень общий, возможно, вы можете найти обходной путь, используя эти ответы).
источник
Вы хотите создать универсальный класс с ограничением типа, которое требует, чтобы используемые классы соответствовали ему
SomeProtocol
, например так:источник
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
в массив?let foo = SomeClass<MyMemberClass>()
Equatable
соответствии - без этого вы можете использовать свой точный код. Может быть, отправить запрос об ошибке / функции?В Swift есть специальный класс протоколов, который не обеспечивает полиморфизм над типами, которые его реализуют. Такие протоколы используют
Self
илиassociatedtype
ключевые слова в своих определениях (иEquatable
является одним из них).В некоторых случаях можно использовать обертку со стертым типом, чтобы сделать вашу коллекцию гомоморфной. Ниже приведен пример.
источник
Ограниченное решение, которое я нашел, - пометить протокол как протокол только для класса. Это позволит вам сравнивать объекты с помощью оператора «===». Я понимаю, что это не сработает для структур и т. Д., Но в моем случае это было достаточно хорошо.
источник
protocols
, еслиaddElement
вызывается более одного раза с одним и тем же объектом?removeElement()
до добавления нового элемента, если хотите избежать дублирования.Решение довольно простое:
источник
Equatable
протокол. Это имеет огромное значение.SomeProtocol
типизированным массивом.Equatable
соответствие требуется только для удаления элементов из массива. Мое решение - улучшенная версия решения @almas, потому что его можно использовать с любым типом Swift, соответствующимEquatable
протоколу.Я полагаю, что ваша основная цель - хранить коллекцию объектов, соответствующую какому-либо протоколу, добавлять в эту коллекцию и удалять из нее. Это функциональность, как указано в вашем клиенте "SomeClass". Равное наследование требует себя, и это не нужно для этой функциональности. Мы могли бы выполнить эту работу в массивах в Obj-C, используя функцию «index», которая может принимать пользовательский компаратор, но это не поддерживается в Swift. Поэтому самое простое решение - использовать словарь вместо массива, как показано в коде ниже. Я предоставил getElements (), который вернет вам требуемый массив протоколов. Поэтому любой, кто использует SomeClass, даже не знает, что для реализации использовался словарь.
Поскольку в любом случае вам понадобится какое-то отличительное свойство для разделения ваших объектов, я предположил, что это «имя». Пожалуйста, убедитесь, что ваш do element.name = "foo" при создании нового экземпляра SomeProtocol. Если имя не задано, вы все равно можете создать экземпляр, но он не будет добавлен в коллекцию, а addElement () вернет «false».
источник
Я нашел не совсем чистое решение Swift в этом посте: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
Хитрость заключается в том, чтобы соответствовать,
NSObjectProtocol
как это вводитisEqual()
. Поэтому вместо использованияEquatable
протокола и его использования по умолчанию==
вы можете написать свою собственную функцию, чтобы найти элемент и удалить его.Вот реализация вашей
find(array, element) -> Int?
функции:Примечание. В этом случае ваши объекты, соответствующие требованиям,
SomeProtocol
должны наследоваться отNSObject
.источник