Eu quero criar uma classe que possa armazenar objetos em conformidade com um determinado protocolo. Os objetos devem ser armazenados em uma matriz digitada. De acordo com a documentação da Swift, os protocolos podem ser usados como tipos:
Por ser um tipo, você pode usar um protocolo em muitos lugares onde outros tipos são permitidos, incluindo:
- Como um tipo de parâmetro ou tipo de retorno em uma função, método ou inicializador
- Como o tipo de uma constante, variável ou propriedade
- Como o tipo de itens em uma matriz, dicionário ou outro contêiner
No entanto, o seguinte gera erros do compilador:
O protocolo 'SomeProtocol' só pode ser usado como uma restrição genérica porque possui requisitos de tipo Próprio ou associado
Como você deve resolver isso:
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)
}
}
}
ios
swift
generics
swift-protocols
rude
fonte
fonte
Respostas:
Você encontrou uma variante de um problema com protocolos no Swift para os quais ainda não existe uma boa solução.
Consulte também Estendendo a matriz para verificar se está classificada no Swift? , ele contém sugestões sobre como solucionar o problema que pode ser adequado ao seu problema específico (sua pergunta é muito genérica, talvez você possa encontrar uma solução alternativa usando essas respostas).
fonte
Você deseja criar uma classe genérica, com uma restrição de tipo que requer que as classes usadas com ela estejam em conformidade
SomeProtocol
, assim:fonte
SomeProtocol
-let protocolGroup: SomeClass<MyMemberClass> = SomeClass()
MyMemberClass
à matriz?let foo = SomeClass<MyMemberClass>()
Equatable
conformidade - sem isso você pode usar seu código exato. Talvez arquive uma solicitação de bug / recurso?Em Swift, existe uma classe especial de protocolos que não fornece polimorfismo sobre os tipos que o implementam. Tais protocolos usam
Self
ouassociatedtype
palavras - chave em suas definições (eEquatable
é um deles).Em alguns casos, é possível usar um invólucro de tipo apagado para tornar sua coleção homomórfica. Abaixo está um exemplo.
fonte
A solução limitada que encontrei é marcar o protocolo como um protocolo somente de classe. Isso permitirá comparar objetos usando o operador '==='. Entendo que isso não funcionará para estruturas, etc., mas foi bom o suficiente no meu caso.
fonte
protocols
, seaddElement
for chamado mais de uma vez com o mesmo objeto?removeElement()
antes de acrescentar o novo elemento se desejar evitar duplicatas.A solução é bem simples:
fonte
Equatable
protocolo. Faz uma enorme diferença.SomeProtocol
em uma matriz digitada.Equatable
a conformidade é necessária apenas para remover elementos da matriz. Minha solução é uma versão aprimorada da solução @almas, pois pode ser usada com qualquer tipo Swift que esteja em conformidade com oEquatable
protocolo.Suponho que seu objetivo principal seja armazenar uma coleção de objetos em conformidade com algum protocolo, adicionar a essa coleção e excluir dela. Essa é a funcionalidade conforme declarada no seu cliente, "SomeClass". A herança equivalente requer auto e isso não é necessário para esta funcionalidade. Poderíamos ter feito esse trabalho em matrizes no Obj-C usando a função "index" que pode levar um comparador personalizado, mas isso não é suportado no Swift. Portanto, a solução mais simples é usar um dicionário em vez de uma matriz, conforme mostrado no código abaixo. Eu forneci getElements (), que retornará a matriz de protocolo que você queria. Portanto, qualquer pessoa que use o SomeClass nem saberia que um dicionário foi usado para implementação.
Como em qualquer caso, você precisaria de alguma propriedade distinta para separar seus objetivos, presumi que seja "nome". Certifique-se de que você faça element.name = "foo" ao criar uma nova instância de SomeProtocol. Se o nome não estiver definido, você ainda poderá criar a instância, mas ela não será adicionada à coleção e addElement () retornará "false".
fonte
Encontrei uma solução Swift não pura pura nessa postagem do blog: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
O truque é se conformar com o
NSObjectProtocol
que é introduzidoisEqual()
. Portanto, em vez de usar oEquatable
protocolo e seu uso padrão de==
você pode escrever sua própria função para encontrar o elemento e removê-lo.Aqui está a implementação da sua
find(array, element) -> Int?
função:Nota: Nesse caso, seus objetos conformes
SomeProtocol
devem herdar deNSObject
.fonte