Digamos que eu tenha um storyboard que contém UINavigationController
um controlador de visualização inicial. Seu controlador de visualização raiz é uma subclasse de UITableViewController
, que é BasicViewController
. Ele IBAction
está conectado ao botão de navegação direito da barra de navegação.
A partir daí, gostaria de usar o storyboard como um modelo para outras visualizações sem ter que criar storyboards adicionais. Digamos que essas visualizações tenham exatamente a mesma interface, mas com o controlador de visualização raiz da classe SpecificViewController1
e SpecificViewController2
quais são as subclasses de BasicViewController
.
Esses 2 controladores de visualização teriam a mesma funcionalidade e interface, exceto para o IBAction
método.
Seria assim:
@interface BasicViewController : UITableViewController
@interface SpecificViewController1 : BasicViewController
@interface SpecificViewController2 : BasicViewController
Posso fazer algo assim?
Posso apenas instanciar o storyboard de, BasicViewController
mas ter o controlador de visualização raiz para a subclasse SpecificViewController1
e SpecificViewController2
?
Obrigado.
Respostas:
ótima pergunta - mas, infelizmente, apenas uma resposta fraca. Não acredito que atualmente seja possível fazer o que você propõe, porque não há inicializadores no UIStoryboard que permitem substituir o controlador de visualização associado ao storyboard conforme definido nos detalhes do objeto no storyboard na inicialização. É na inicialização que todos os elementos da IU no stoaryboard são vinculados às suas propriedades no controlador de visualização.
Ele será inicializado por padrão com o controlador de visualização que é especificado na definição do storyboard.
Se você está tentando obter a reutilização de elementos de interface do usuário que você criou no storyboard, eles ainda devem ser vinculados ou associados às propriedades em que o controlador de visualização os esteja usando para que possam "informar" o controlador de visualização sobre os eventos.
Copiar sobre um layout de storyboard não é um grande problema, especialmente se você só precisa de um design semelhante para 3 visualizações, no entanto, se precisar, deve certificar-se de que todas as associações anteriores foram apagadas, ou ocorrerá falhas ao tentar para se comunicar com o controlador de visualização anterior. Você será capaz de reconhecê-los como mensagens de erro KVO na saída do log.
Algumas abordagens que você pode adotar:
armazene os elementos da interface do usuário em um UIView - em um arquivo xib e instancie-o de sua classe base e adicione-o como uma subvisão na visão principal, normalmente self.view. Então, você simplesmente usaria o layout de storyboard com controladores de visualização basicamente em branco mantendo seu lugar no storyboard, mas com a subclasse de controlador de visualização correta atribuída a eles. Como eles herdariam da base, eles obteriam essa visão.
crie o layout no código e instale-o a partir de seu controlador de visualização de base. Obviamente, essa abordagem anula o propósito de usar o storyboard, mas pode ser o caminho a percorrer no seu caso. Se você tiver outras partes do aplicativo que se beneficiariam da abordagem do storyboard, não há problema em desviar aqui e ali, se apropriado. Neste caso, como acima, você apenas usaria controladores de visualização de banco com sua subclasse atribuída e deixaria o controlador de visualização de base instalar a IU.
Seria bom se a Apple descobrisse uma maneira de fazer o que você propõe, mas o problema de ter os elementos gráficos pré-vinculados à subclasse do controlador ainda seria um problema.
tenha um ótimo ano novo !! fique bem
fonte
O código de linha que procuramos é:
Em Storyboard -> adicionar UIViewController, dê a ele um nome de classe ParentVC.
fonte
class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
self
não muda. Portanto, a inspeção do objeto (por exemplo, leitura de _ivar / valores de propriedade) depoisobject_setClass
pode causar travamentos.Como afirma a resposta aceita, não parece que seja possível fazer com storyboards.
Minha solução é usar o Nib's - assim como os desenvolvedores os usavam antes dos storyboards. Se você deseja ter um controlador de visualização reutilizável e subclassível (ou mesmo uma visualização), minha recomendação é usar o Nibs.
Quando você conecta todas as suas saídas ao "Proprietário do Arquivo" no,
MyViewController.xib
você NÃO está especificando em qual classe o Nib deve ser carregado, você está apenas especificando pares de valores-chave: " esta visão deve ser conectada a este nome de variável de instância ." Ao chamar[SubclassMyViewController alloc] initWithNibName:
o processo de inicialização, especifique qual controlador de visualização será usado para " controlar " a visualização que você criou na ponta.fonte
É possível fazer com que um storyboard instancie diferentes subclasses de um controlador de visualização customizado, embora envolva uma técnica um pouco heterodoxa: substituir o
alloc
método para o controlador de visualização. Quando o controlador de visualização customizado é criado, o método de alocação sobrescrito retorna de fato o resultado da execuçãoalloc
na subclasse.Devo começar a resposta com a ressalva de que, embora eu tenha testado em vários cenários e não tenha recebido erros, não posso garantir que ele irá lidar com configurações mais complexas (mas não vejo razão para que não funcione) . Além disso, não enviei nenhum aplicativo usando esse método, portanto, há uma chance remota de que ele seja rejeitado pelo processo de revisão da Apple (embora, novamente, não vejo razão para isso).
Para fins de demonstração, tenho uma subclasse de
UIViewController
chamadoTestViewController
, que tem um UILabel IBOutlet e um IBAction. Em meu storyboard, adicionei um controlador de visualização eTestViewController
alterei sua classe para , e conectei o IBOutlet a um UILabel e o IBAction a um UIButton. Apresento o TestViewController por meio de uma segue modal acionada por um UIButton no viewController anterior.Para controlar qual classe é instanciada, adicionei uma variável estática e métodos de classe associados para obter / definir a subclasse a ser usada (eu acho que pode-se adotar outras maneiras de determinar qual subclasse deve ser instanciada):
TestViewController.m:
Para meu teste, tenho duas subclasses de
TestViewController
:RedTestViewController
eGreenTestViewController
. Cada uma das subclasses tem propriedades adicionais e cada substituiçãoviewDidLoad
para alterar a cor de fundo da visualização e atualizar o texto do IBOutlet UILabel:RedTestViewController.m:
GreenTestViewController.m:
Em algumas ocasiões, posso querer instanciar-
TestViewController
se, em outras ocasiõesRedTestViewController
ouGreenTestViewController
. No controlador de visualização anterior, faço isso aleatoriamente da seguinte maneira:Observe que o
setClassForStoryBoard
método verifica se o nome da classe solicitado é de fato uma subclasse de TestViewController, para evitar confusões. A referência acimaBlueTestViewController
para testar esta funcionalidade.fonte
tente isso, após instantiateViewControllerWithIdentifier.
gostar :
fonte
EXC_BAD_ACCESS
, então não recomendo isso.init
também não será chamada. Essas restrições tornam todas as abordagens inutilizáveis.Baseando-se particularmente em nickgzzjr e Jiří Zahálka, além de comentários no segundo do CocoaBob, preparei um método genérico curto fazendo exatamente o que o OP precisa. Você só precisa verificar o nome do storyboard e Exibir ID do storyboard dos controladores
Opcionais são adicionados para evitar forçar o desempacotamento (avisos do swiftlint), mas o método retorna os objetos corretos.
fonte
Embora não seja estritamente uma subclasse, você pode:
Aqui está um exemplo de um tutorial do Bloc que escrevi, criando
ViewController
uma subclasse comWhiskeyViewController
:Isso permite que você crie subclasses de subclasses de view controller no storyboard. Você pode então usar
instantiateViewControllerWithIdentifier:
para criar subclasses específicas.Essa abordagem é um pouco inflexível: as modificações posteriores no storyboard para o controlador da classe base não se propagam para a subclasse. Se você tem muitas subclasses, pode ficar melhor com uma das outras soluções, mas isso servirá em uma pitada.
fonte
initWithCoder:
, não têm um relacionamento herdado. Esse tipo de relacionamento não é compatível com arquivos de storyboard.O método Objc_setclass não cria uma instância de childvc. Mas enquanto sai de childvc, deinit de childvc está sendo chamado. Como não há memória alocada separadamente para childvc, o aplicativo trava. O Basecontroller tem uma instância, enquanto o filho vc não tem.
fonte
Se você não depende muito de storyboards, pode criar um arquivo .xib separado para o controlador.
Defina o proprietário do arquivo apropriado e saídas para o
MainViewController
e substituainit(nibName:bundle:)
no VC principal para que seus filhos possam acessar o mesmo Nib e suas saídas.Seu código deve ser assim:
E seu filho VC será capaz de reutilizar a ponta dos pais:
fonte
Pegando respostas aqui e ali, eu encontrei esta solução bacana.
Crie um controlador de visualização pai com esta função.
Isso permite que o compilador garanta que o controlador de visualização filho herde do controlador de visualização pai.
Então, sempre que quiser seguir para este controlador usando uma subclasse, você pode fazer:
A parte legal é que você pode adicionar uma referência de storyboard a si mesmo e, em seguida, continuar chamando o "próximo" controlador de visualização filho.
fonte
Provavelmente, a maneira mais flexível é usar visualizações reutilizáveis.
(Crie uma visualização em arquivo XIB separado ou
Container view
adicione-a a cada cena do controlador de visualização de subclasse no storyboard)fonte
Existe uma solução simples e óbvia para o dia-a-dia.
Basta colocar o storyboard / controlador existente dentro do novo storyobard / controlador. IE como uma visualização de contêiner.
Este é o conceito exatamente análogo a "subclassificar", para controladores de visualização.
Tudo funciona exatamente como em uma subclasse.
Assim como você costuma colocar uma subvisão de visão dentro de outra visão , naturalmente você costuma colocar um controlador de visão dentro de outro controlador de visão .
De que outra forma você poderia fazer isso?
É uma parte básica do iOS, tão simples quanto o conceito de "subvisão".
É assim tão fácil ...
Agora você obviamente tem
list
que fazer o que quiser cometc etc.
As visualizações de contêiner são "exatamente como" subclasses da mesma forma que "subvisualizações" são "exatamente como" subclasses.
Claro, obviamente, você não pode "subclassificar um layout" - o que isso significa?
("Subclasse" refere-se ao software OO e não tem conexão com "layouts".)
Obviamente, quando você deseja reutilizar uma visualização, basta subvisualizá-la dentro de outra visualização.
Quando você quiser reutilizar um layout de controlador, basta visualizá-lo em outro controlador.
Este é o mecanismo mais básico do iOS !!
Nota - há anos tem sido trivial carregar dinamicamente outro controlador de visualização como uma visualização de contêiner. Explicado na última seção: https://stackoverflow.com/a/23403979/294884
Observação - "_sb" é apenas uma macro óbvia que usamos para economizar digitação,
fonte
Obrigado pela resposta inspiradora de @ Jiří Zahálka, eu respondi minha solução há 4 anos aqui , mas @Sayka me sugeriu postá-la como uma resposta, então aqui está.
Em meus projetos, normalmente, se estou usando o Storyboard para uma subclasse UIViewController, sempre preparo um método estático chamado
instantiate()
nessa subclasse, para criar uma instância do Storyboard facilmente. Portanto, para resolver a questão do OP, se quisermos compartilhar o mesmo Storyboard para diferentes subclasses, podemos simplesmentesetClass()
ir para essa instância antes de retorná-la.fonte
O comentário de Cocoabob da resposta de Jiří Zahálka me ajudou a encontrar essa solução e funcionou bem.
fonte