Eu gostaria de criar uma função abstrata em linguagem rápida. É possível?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Respostas:
Não há conceito abstrato em Swift (como Objective-C), mas você pode fazer isso:
fonte
assert(false, "This method must be overriden by the subclass")
.fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
no Swift que será executado nas versões de lançamento e também elimina a necessidade de uma declaração de retorno. EDIT: Só descobri que este método é basicamente igualfatalError()
, mas é a forma mais adequada (Better documentação, introduzido em Swift junto comprecondition()
,assert()
eassertionFailure()
, leia aqui )O que você deseja não é uma classe base, mas um protocolo.
Se você não fornecer abstractFunction em sua classe, é um erro.
Se você ainda precisar da classe básica para outro comportamento, poderá fazer o seguinte:
fonte
Eu porto uma quantidade razoável de código de uma plataforma que suporta classes base abstratas para o Swift e me deparo muito com isso. Se o que você realmente deseja é a funcionalidade de uma classe base abstrata, isso significa que essa classe serve tanto como uma implementação da funcionalidade de classe baseada em compartilhamento (caso contrário, seria apenas uma interface / protocolo) E define métodos que devem ser implementados por classes derivadas.
Para fazer isso no Swift, você precisará de um protocolo e uma classe base.
Observe que a classe base implementa o (s) método (s) compartilhado (s), mas não implementa o protocolo (uma vez que não implementa todos os métodos).
Então, na classe derivada:
A classe derivada herda sharedFunction da classe base, ajudando-a a satisfazer essa parte do protocolo, e o protocolo ainda exige que a classe derivada implemente abstractFunction.
A única desvantagem real desse método é que, como a classe base não implementa o protocolo, se você tiver um método da classe base que precise acessar uma propriedade / método do protocolo, será necessário substituí-lo na classe derivada e, a partir daí, chamar a classe base (via super) passando
self
para que a classe base tenha uma instância do protocolo com o qual realizar seu trabalho.Por exemplo, digamos que sharedFunction necessário para chamar abstractFunction. O protocolo permaneceria o mesmo e as classes agora pareceriam:
Agora, o sharedFunction da classe derivada está satisfazendo essa parte do protocolo, mas a classe derivada ainda é capaz de compartilhar a lógica da classe base de uma maneira razoavelmente direta.
fonte
Esta parece ser a maneira "oficial" de como a Apple está lidando com métodos abstratos no UIKit. Dê uma olhada
1. Coloque o método abstrato em um protocolo 2. Escreva sua classe base 3. Escreva a subclasse (s). Aqui está, como você usa tudo issoUITableViewController
e como ele está trabalhandoUITableViewDelegate
. Uma das primeiras coisas que você faz, é adicionar uma linha:delegate = self
. Bem, esse é exatamente o truque.Verifique com o Playground para ver a saída.
Algumas observações
UITableViewController
implementa,UITableViewDelegate
mas ainda precisa ser registrado como delegado, definindo explicitamente adelegate
propriedadefonte
getComments
método no delegado pai. Existem vários tipos de comentários e quero os relevantes para cada objeto. Portanto, quero que as subclasses não sejam compiladas quando o fizer,delegate.getComments()
se não substituir esse método. O VC apenas sabe que possui umParentDelegate
objeto chamadodelegate
, ouBaseClassX
no seu exemplo, masBaseClassX
não possui o método abstraído. Eu precisaria que o VC soubesse especificamente que está usando oSubclassedDelegate
.Uma maneira de fazer isso é usar um fechamento opcional definido na classe base, e os filhos podem optar por implementá-lo ou não.
fonte
Bem, eu sei que estou atrasado para o jogo e que posso estar aproveitando as mudanças que aconteceram. Me desculpe por isso.
De qualquer forma, gostaria de contribuir com minha resposta, porque adoro fazer testes e as soluções com o
fatalError()
AFAIK não são testáveis e as que têm exceções são muito mais difíceis de testar.Eu sugeriria usar uma abordagem mais rápida . Seu objetivo é definir uma abstração que possua alguns detalhes em comum, mas que não esteja totalmente definida, ou seja, o (s) método (s) abstrato (s). Use um protocolo que defina todos os métodos esperados na abstração, os que estão definidos e também os que não são. Em seguida, crie uma extensão de protocolo que implemente os métodos definidos no seu caso. Finalmente, qualquer classe derivada deve implementar o protocolo, o que significa todos os métodos, mas os que fazem parte da extensão do protocolo já têm sua implementação.
Estendendo seu exemplo com uma função concreta:
Observe que, ao fazer isso, o compilador é novamente seu amigo. Se o método não for "substituído", você receberá um erro no tempo de compilação, em vez daqueles com os quais você obteria
fatalError()
ou exceções que aconteceriam no tempo de execução.fonte
Entendo o que você está fazendo agora, acho melhor você usar um protocolo
Então, você apenas está em conformidade com o protocolo:
Se a sua classe também for uma subclasse, os protocolos seguirão a superclasse:
fonte
Usando a
assert
palavra-chave para aplicar métodos abstratos:No entanto, como Steve Waddicor mencionou, você provavelmente quer um
protocol
.fonte
Eu entendi a pergunta e estava procurando a mesma solução. Protocolos não são os mesmos que métodos abstratos.
Em um protocolo, você precisa especificar que sua classe está em conformidade com esse protocolo, um método abstrato significa que você deve substituir esse método.
Em outras palavras, os protocolos são opcionais, você precisa especificar a classe base e o protocolo; se você não especificar o protocolo, não precisará substituir esses métodos.
Um método abstrato significa que você deseja uma classe base, mas precisa implementar seu próprio método ou dois, o que não é o mesmo.
Eu preciso do mesmo comportamento, por isso estava procurando uma solução. Eu acho que Swift está faltando esse recurso.
fonte
Há outra alternativa para esse problema, embora ainda haja uma desvantagem quando comparada à proposta de @ jaumard; requer uma declaração de retorno. Embora eu perca o ponto de exigi-lo, porque consiste em lançar diretamente uma exceção:
E depois:
O que vier depois disso é inacessível, então não vejo por que forçar o retorno.
fonte
AbstractMethodException().raise()
?Não sei se será útil, mas tive um problema semelhante com o método abstraído ao tentar criar o jogo SpritKit. O que eu queria é uma classe Animal abstrata que possua métodos como move (), run () etc, mas nomes de sprites (e outras funcionalidades) devem ser fornecidos pelos filhos da classe. Então, acabei fazendo algo assim (testado para o Swift 2):
fonte