Embora eu ache que posso responder à sua pergunta, não é uma resposta de que você goste.
TL; DR: as @objc
funções podem não estar atualmente em extensões de protocolo. Em vez disso, você poderia criar uma classe base, embora essa não seja uma solução ideal.
Extensões de protocolo e Objective-C
Em primeiro lugar, esta pergunta / resposta ( Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c ) parece sugerir que, devido à forma como as extensões de protocolo são despachadas sob o capô, os métodos declarados em extensões de protocolo não são visíveis para a objc_msgSend()
função, e portanto, não são visíveis para o código Objective-C. Uma vez que o método que você está tentando definir em sua extensão precisa ser visível para Objective-C (para que UIKit
possa usá-lo), ele grita com você para não incluir @objc
, mas uma vez que você o inclui, ele grita com você porque @objc
não é permitido em extensões de protocolo. Provavelmente, isso ocorre porque as extensões de protocolo não podem ser visíveis para Objective-C no momento.
Também podemos ver que a mensagem de erro uma vez que adicionamos os @objc
estados "@objc só pode ser usado com membros de classes, protocolos @objc e extensões concretas de classes." Esta não é uma aula; uma extensão para um protocolo @objc não é o mesmo que estar na própria definição de protocolo (ou seja, em requisitos), e a palavra "concreto" sugere que uma extensão de protocolo não conta como uma extensão de classe concreta.
Gambiarra
Infelizmente, isso impede completamente que você use extensões de protocolo quando as implementações padrão devem ser visíveis para estruturas Objective-C. No início, pensei que talvez @objc
não fosse permitido em sua extensão de protocolo porque o Compilador Swift não poderia garantir que os tipos em conformidade seriam classes (mesmo que você tenha especificado especificamente UIViewController
). Então eu coloquei um class
requisito P1
. Isso não funcionou.
Talvez a única solução alternativa seja simplesmente usar uma classe base em vez de um protocolo aqui, mas isso obviamente não é completamente ideal porque uma classe pode ter apenas uma única classe base, mas estar em conformidade com vários protocolos.
Se você escolher seguir esse caminho, leve esta questão ( Método de protocolo opcional Swift 3 ObjC não chamado na subclasse ) em consideração. Parece que outro problema atual no Swift 3 é que as subclasses não herdam automaticamente as implementações de requisitos de protocolo opcionais de sua superclasse. A resposta a essas perguntas usa uma adaptação especial de @objc
para contorná-la.
Relatando o problema
Acho que isso já está sendo discutido entre aqueles que trabalham nos projetos de código aberto do Swift, mas você pode ter certeza que eles estão cientes usando o Bug Reporter da Apple , que provavelmente acabaria chegando à equipe do Swift Core, ou o relator de bug do Swift . No entanto, qualquer um deles pode achar seu bug muito amplo ou já conhecido. A equipe do Swift também pode considerar o que você está procurando como um novo recurso de idioma; nesse caso, você deve primeiro verificar as listas de discussão .
Atualizar
Em dezembro de 2016, esse problema foi relatado à comunidade Swift. O problema ainda está marcado como aberto com prioridade média, mas o seguinte comentário foi adicionado:
Isso é intencional. Não há como adicionar a implementação do método a todos os adotantes, pois a extensão poderia ser adicionada após a conformidade com o protocolo. Suponho que poderíamos permitir se a extensão estiver no mesmo módulo que o protocolo.
Como seu protocolo está no mesmo módulo que sua extensão, no entanto, você poderá fazer isso em uma versão futura do Swift.
Atualização 2
Em fevereiro de 2017, esse problema foi oficialmente encerrado como "Não vou fazer" por um dos membros da equipe central da Swift com a seguinte mensagem:
Isso é intencional: as extensões de protocolo não podem introduzir pontos de entrada @objc devido às limitações do tempo de execução do Objective-C. Se você deseja adicionar pontos de entrada @objc a NSObject, estenda NSObject.
Estender NSObject
ou mesmo UIViewController
não vai realizar exatamente o que você deseja, mas infelizmente não parece que será possível.
Em um futuro de (muito) longo prazo, podemos ser capazes de eliminar @objc
totalmente a dependência de métodos, mas esse momento provavelmente não chegará tão cedo, uma vez que as estruturas do Cocoa não são atualmente escritas em Swift (e não podem ser até que tenha uma ABI estável) .
Atualização 3
A partir do outono de 2019, isso está se tornando um problema menor porque mais e mais frameworks da Apple estão sendo escritos em Swift. Por exemplo, se você usar em SwiftUI
vez de UIKit
, contorna o problema totalmente porque @objc
nunca seria necessário ao se referir a um SwiftUI
método.
As estruturas da Apple escritas em Swift incluem:
- SwiftUI
- RealityKit
- Combinar
- CryptoKit
Seria de se esperar que esse padrão continuasse ao longo do tempo, agora que o Swift é oficialmente ABI e módulo estável a partir do Swift 5.0 e 5.1, respectivamente.
@objc