Estou tentando converter o código-fonte do meu projeto de Swift 3 para Swift 4. Um aviso que o Xcode está me dando é sobre meus seletores.
Por exemplo, adiciono um destino a um botão usando um seletor regular como este:
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
Este é o aviso que mostra:
O argumento '#selector' refere-se ao método de instância 'myAction ()' em 'ViewController' que depende da inferência de atributo '@objc' descontinuada no Swift 4
Adicione '@objc' para expor esse método de instância ao Objective-C
Agora, bater Fix
na mensagem de erro faz isso com a minha função:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
Eu realmente não quero renomear todas as minhas funções para incluir a @objc
marca e estou assumindo que isso não é necessário.
Como reescrevo o seletor para lidar com a depreciação?
Pergunta relacionada:
@objc
é agora necessária, de modo a expô-los a Obj-C, e, portanto, usar-se com selectores.@objc
? Isso é um pouco chato, mas geralmente faço essas funções privadas, exigindo que eu a marque de@objc
qualquer maneira.@objcMembers
para expor todos os membros compatíveis com Obj-C ao Obj-C, mas eu não recomendaria isso, a menos que você realmente precise que toda a sua classe seja exposta.Respostas:
A correção está correta - não há nada sobre o seletor que você possa alterar para tornar o método ao qual ele se refere exposto ao Objective-C.
Todo o motivo desse aviso é o resultado do SE-0160 . Antes do Swift 4,
internal
deduzia-se que membros compatíveis com Objective-C ou superior deNSObject
classes herdadas eram@objc
e expostos ao Objective-C, permitindo que fossem chamados usando seletores (como o tempo de execução do Obj-C é necessário para procurar o método implementação para um determinado seletor).No entanto, no Swift 4, esse não é mais o caso. Agora, deduz-se apenas que declarações muito específicas são
@objc
, por exemplo, substituições de@objc
métodos, implementações de@objc
requisitos de protocolo e declarações com atributos que implicam@objc
, como@IBOutlet
.A motivação por trás disso, conforme detalhado na proposta vinculada acima , é primeiramente evitar sobrecargas de método em
NSObject
classes herdadas colidam entre si devido a terem seletores idênticos. Em segundo lugar, ajuda a reduzir o tamanho binário por não precisar gerar thunks para membros que não precisam ser expostos ao Obj-C e, por outro lado, melhora a velocidade da vinculação dinâmica.Se você deseja expor um membro ao Obj-C, é necessário marcá-lo como
@objc
, por exemplo:(o migrante deve fazer isso automaticamente para você com seletores ao executar com a opção "minimizar inferência" selecionada)
Para expor um grupo de membros ao Obj-C, você pode usar um
@objc extension
:Isso expõe todos os membros definidos a ele ao Obj-C e gera um erro em qualquer membro que não possa ser exposto ao Obj-C (a menos que seja explicitamente marcado como
@nonobjc
).Se você tem uma classe na qual você precisa que todos os membros compatíveis com Obj-C sejam expostos ao Obj-C, é possível marcar a classe como
@objcMembers
:Agora, todos os membros que podem ser deduzidos
@objc
serão. No entanto, eu não recomendaria fazer isso, a menos que você realmente precise de todos os membros expostos ao Obj-C, dadas as desvantagens acima mencionadas de ter membros desnecessariamente expostos.fonte
@IBAction
também são automaticamente@objc
? esse não era o caso até agora, mas seria lógico. EDIT: nvm, a proposta afirma claramente que@IBAction
é suficiente para um método ser@objc
.Como documentação oficial da Apple . você precisa usar @objc para chamar seu método seletor.
fonte
A partir de, acho que o Swift 4.2, tudo que você precisa fazer é atribuir @IBAction ao seu método e você pode evitar essa anotação boba do @objc
`` ``
fonte
Como já mencionado em outras respostas, não há como evitar a
@objc
anotação para seletores.Porém, o aviso mencionado no OP pode ser silenciado executando as seguintes etapas:
Off
abaixo está a captura de tela que ilustra as etapas mencionadas acima:
Espero que isto ajude
fonte
Se você precisar de membros c objetivos no seu controlador de exibição, adicione @objcMembers na parte superior do controlador de exibição. E você pode evitar isso adicionando IBAction no seu código.
Certifique-se de conectar esta tomada no storyboard.
fonte