Existe uma maneira embutida de ir de um UIView
para o seu UIViewController
? Eu sei que você pode ir de UIViewController
sua UIView
via, [self view]
mas eu queria saber se existe uma referência reversa?
fonte
Existe uma maneira embutida de ir de um UIView
para o seu UIViewController
? Eu sei que você pode ir de UIViewController
sua UIView
via, [self view]
mas eu queria saber se existe uma referência reversa?
Como essa é a resposta aceita há muito tempo, sinto que preciso corrigi-la com uma resposta melhor.
Alguns comentários sobre a necessidade:
Um exemplo de como implementá-lo é o seguinte:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
A visualização faz interface com seu representante (como UITableView
faz, por exemplo) e não se importa se está implementada no controlador de visualização ou em qualquer outra classe que você acaba usando.
Minha resposta original é a seguinte: Eu não recomendo isso, nem o restante das respostas em que é alcançado o acesso direto ao controlador de exibição
Não há uma maneira integrada de fazer isso. Enquanto você pode obter em torno dele, adicionando uma IBOutlet
no UIView
e ligando estes no Interface Builder, isso não é recomendado. A visualização não deve saber sobre o controlador de visualização. Em vez disso, você deve fazer o que o @Phil M sugere e criar um protocolo para ser usado como delegado.
Usando o exemplo postado por Brock, modifiquei-o para que seja uma categoria de UIView, em vez de UIViewController, e o tornei recursivo para que qualquer subvisão possa (espero) encontrar o UIViewController pai.
Para usar esse código, adicione-o a um novo arquivo de classe (nomeiei meu "UIKitCategories") e remova os dados da classe ... copie a interface @ no cabeçalho e a implementação @ no arquivo .m. Em seu projeto, #import "UIKitCategories.h" e use no código UIView:
fonte
UIView
é uma subclasse deUIResponder
.UIResponder
estabelece o método-nextResponder
com uma implementação que retornanil
.UIView
substitui esse método, conforme documentado emUIResponder
(por algum motivo, em vez de emUIView
) da seguinte maneira: se a visualização tiver um controlador de visualização, ele será retornado por-nextResponder
. Se não houver um controlador de exibição, o método retornará a superview.Adicione isso ao seu projeto e você estará pronto para começar.
Agora
UIView
tem um método de trabalho para retornar o controlador de exibição.fonte
UIView
e oUIViewController
. A resposta de Phil M com recursão é o caminho a percorrer.Eu sugeriria uma abordagem mais leve para percorrer toda a cadeia de respostas sem precisar adicionar uma categoria no UIView:
fonte
Combinando várias respostas já fornecidas, eu também as envio com a minha implementação:
A categoria faz parte da minha biblioteca estática habilitada para ARC que eu envio em todos os aplicativos que eu criar. Foi testado várias vezes e não encontrei nenhum problema ou vazamento.
PS: Você não precisa usar uma categoria como eu fiz se a exibição em questão for uma subclasse sua. Neste último caso, basta colocar o método na sua subclasse e você estará pronto.
fonte
Mesmo que isso possa ser tecnicamente resolvido como recomenda a pgb , IMHO, essa é uma falha de design. A visualização não precisa estar ciente do controlador.
fonte
I modificado de resposta para que eu possa passar qualquer ponto de vista, botão, etiqueta etc. para obtê-lo de pai
UIViewController
. Aqui está o meu código.Editar versão do Swift 3
Edição 2: - Extensão rápida
fonte
Não esqueça que você pode obter acesso ao controlador de visualização raiz da janela da qual a visualização é uma subvisão. A partir daí, se você estiver, por exemplo, usando um controlador de visualização de navegação e desejar inserir uma nova visualização nele:
Você precisará configurar corretamente a propriedade rootViewController da janela primeiro. Faça isso quando criar o controlador, por exemplo, no delegado do aplicativo:
fonte
[[self navigationController] view]
é a (sub) visualização "principal" da janela, arootViewController
propriedade da janela deve ser configurada paranavigationController
controlar a visualização "principal" imediatamente.Embora essas respostas sejam tecnicamente corretas, incluindo a Ushox, acho que a maneira aprovada é implementar um novo protocolo ou reutilizar um já existente. Um protocolo isola o observador do observado, como colocar um slot de correio entre eles. Com efeito, é isso que Gabriel faz através da invocação do método pushViewController; a view "sabe" que é um protocolo adequado solicitar educadamente ao seu navigationController que forneça uma visualização, pois o viewController está em conformidade com o protocolo navigationController. Embora você possa criar seu próprio protocolo, basta usar o exemplo de Gabriel e reutilizar o protocolo UINavigationController.
fonte
Eu me deparei com uma situação em que tenho um pequeno componente que quero reutilizar e adicionei algum código em uma exibição reutilizável (na verdade, não é muito mais do que um botão que abre a
PopoverController
).Enquanto isso funciona bem no iPad (o que se
UIPopoverController
apresenta, portanto, não precisa de referência aUIViewController
), fazer com que o mesmo código funcione significa fazer uma referência repentinapresentViewController
à suaUIViewController
. Meio inconsistente, certo?Como mencionado anteriormente, não é a melhor abordagem para ter lógica no seu UIView. Mas parecia realmente inútil agrupar as poucas linhas de código necessárias em um controlador separado.
De qualquer maneira, aqui está uma solução rápida, que adiciona uma nova propriedade a qualquer UIView:
fonte
Não acho que seja "péssima" descobrir quem é o controlador de exibição em alguns casos. O que poderia ser uma má idéia é salvar a referência a este controlador, pois ele pode mudar da mesma forma que as superviews. No meu caso, tenho um getter que atravessa a cadeia de respostas.
//.h
//.m
fonte
O loop do while mais simples para encontrar o viewController.
fonte
Swift 4
(mais conciso que as outras respostas)
Meu caso de uso para que eu preciso para acessar a exibição primeiro
UIViewController
: Eu tenho um objeto que envolve em torno deAVPlayer
/AVPlayerViewController
e eu quero fornecer um simplesshow(in view: UIView)
método que irá incorporarAVPlayerViewController
emview
. Para isso, eu preciso de acessoview
éUIViewController
.fonte
Isso não responde diretamente à pergunta, mas faz uma suposição sobre a intenção da pergunta.
Se você tem uma visão e, nessa visão, precisa chamar um método em outro objeto, como o controlador de visão, é possível usar o NSNotificationCenter.
Primeiro, crie sua sequência de notificações em um arquivo de cabeçalho
Na sua opinião, ligue para postNotificationName:
Então, no seu controlador de exibição, você adiciona um observador. Eu faço isso em viewDidLoad
Agora (também no mesmo controlador de exibição) implemente seu método copyString: como representado no @selector acima.
Não estou dizendo que essa é a maneira certa de fazer isso, apenas parece mais limpo do que executar a cadeia de resposta inicial. Usei esse código para implementar um UIMenuController em um UITableView e passar o evento de volta ao UIViewController para que eu possa fazer algo com os dados.
fonte
Certamente é uma má idéia e um design errado, mas tenho certeza de que todos podemos desfrutar de uma solução Swift da melhor resposta proposta por @Phil_M:
Se sua intenção é fazer coisas simples, como mostrar um diálogo modal ou dados de rastreamento, isso não justifica o uso de um protocolo. Eu pessoalmente guardo essa função em um objeto utilitário, você pode usá-la de qualquer coisa que implemente o protocolo UIResponder como:
Todo o crédito a @Phil_M
fonte
Talvez eu esteja atrasado aqui. Mas nesta situação eu não gosto de categoria (poluição). Eu amo assim:
fonte
Solução mais rápida
fonte
sequence
bit). Então, se "swifty" significa "mais funcional", acho que é mais swifty.Versão atualizada para o swift 4: Obrigado por @Phil_M e @ paul-slm
fonte
Versão Swift 4
Exemplo de uso
fonte
Duas soluções a partir do Swift 5.2 :
return
palavra-chave agora 🤓Solução 1:
Solução 2:
fonte
Para a resposta de Phil:
Na linha:
id nextResponder = [self nextResponder];
se self (UIView) não é uma subvisualização da exibição do ViewController, se você conhece a hierarquia de self (UIView), também pode usar:id nextResponder = [[self superview] nextResponder];
...fonte
Minha solução provavelmente seria considerada meio falsa, mas eu tive uma situação semelhante a mayoneez (eu queria trocar de vista em resposta a um gesto em um EAGLView) e obtive o controlador de exibição do EAGL da seguinte maneira:
fonte
EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
.ClassName *object
- com um asterisco.Eu acho que há um caso em que o observado precisa informar o observador.
Vejo um problema semelhante em que o UIView em um UIViewController está respondendo a uma situação e ele precisa primeiro informar ao controlador de exibição pai para ocultar o botão voltar e, após a conclusão, informar ao controlador de exibição pai que ele precisa sair da pilha.
Eu tenho tentado isso com delegados sem sucesso.
Eu não entendo por que isso deve ser uma má idéia?
fonte
Outra maneira fácil é ter sua própria classe de exibição e adicionar uma propriedade do controlador de exibição na classe de exibição. Geralmente, o controlador de visualização cria a visualização e é aí que o controlador pode se definir para a propriedade. Basicamente, é em vez de procurar ao redor (com um pouco de hacking) pelo controlador, fazendo com que o controlador se ajuste à visualização - isso é simples, mas faz sentido, porque é o controlador que "controla" a visualização.
fonte
Se você não fizer o upload para a App Store, também poderá usar um método privado do UIView.
fonte
fonte
Para obter o controlador de uma determinada exibição, pode-se usar a cadeia UIFirstResponder.
fonte
Se o seu rootViewController for UINavigationViewController, que foi configurado na classe AppDelegate,
Onde c é necessário, veja a classe de controladores.
USO:
fonte
Não tem jeito.
O que faço é passar o ponteiro UIViewController para o UIView (ou uma herança apropriada). Me desculpe, eu não posso ajudar com a abordagem da IB para o problema, porque eu não acredito em IB.
Para responder ao primeiro comentarista: às vezes você precisa saber quem ligou para você, porque determina o que você pode fazer. Por exemplo, com um banco de dados, você pode ter somente acesso de leitura ou leitura / gravação ...
fonte