Estou criando um aplicativo iOS usando um Storyboard. O controlador de visualização raiz é um controlador de barra de guias. Estou criando o processo de login / logout, e está funcionando muito bem, mas tenho alguns problemas. Eu preciso saber a melhor maneira de configurar tudo isso.
Quero realizar o seguinte:
- Mostra uma tela de login na primeira vez que o aplicativo é iniciado. Quando eles fizerem login, vá para a primeira guia do Controlador da barra de guias.
- Sempre que iniciarem o aplicativo, verifique se estão logados e pule diretamente para a primeira guia do Controlador de barras de guias raiz.
- Quando eles clicam manualmente em um botão de logout, mostram a tela de logon e limpe todos os dados dos controladores de exibição.
O que eu fiz até agora foi definir o controlador de exibição raiz como Controlador de barra de guias e criar um segue personalizado para o meu controlador de exibição de login. Dentro da minha classe Tab Bar Controller, verifico se eles estão logados dentro do viewDidAppear
método e faço o seguinte:[self performSegueWithIdentifier:@"pushLogin" sender:self];
Também configurei uma notificação para quando a ação de logout precisa ser executada: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutAccount) name:@"logoutAccount" object:nil];
Após o logout, limpo as credenciais do Keychain, execute [self setSelectedIndex:0]
e execute as instruções para mostrar o controlador de exibição de login novamente.
Isso tudo funciona bem, mas estou me perguntando: essa lógica deve estar no AppDelegate? Eu também tenho dois problemas:
- Na primeira vez em que eles iniciam o aplicativo , o Tab Bar Controller é exibido brevemente antes de a execução ser realizada. Eu tentei mover o código para,
viewWillAppear
mas o seguinte não funcionará tão cedo. - Quando eles saem, todos os dados ainda estão dentro de todos os controladores de exibição. Se eles fizerem login em uma nova conta, os dados antigos da conta ainda serão exibidos até que sejam atualizados. Preciso de uma maneira de limpar isso facilmente ao sair.
Estou aberto a refazer isso. Eu considerei tornar a tela de login o controlador de exibição raiz ou criar um controlador de navegação no AppDelegate para lidar com tudo ... Só não tenho certeza qual é o melhor método neste momento.
Respostas:
No appDelegate.m dentro do seu didFinishLaunchingWithOptions
No arquivo SignUpViewController.m
No arquivo MyTabThreeViewController.m
Versão Swift 4
didFinishLaunchingWithOptions no delegado do aplicativo, assumindo que seu controlador de exibição inicial é o TabbarController assinado.
Em Inscrever-se view controller:
MyTabThreeViewController
fonte
AppDelegate
dentroUIViewController
e definirwindow.rootViewController
lá. Não considero isso uma "melhor prática".-1
sem postar uma resposta: stackoverflow.com/a/30664935/1226304AppDelegate
dentroUIViewController
-1 para Armazenar a chave de loginNSUserDefaults
. É muito, muito inseguro para esse tipo de dados!Aqui está o que eu acabei fazendo para realizar tudo. A única coisa que você precisa considerar além disso é (a) o processo de login e (b) onde você está armazenando os dados do aplicativo (nesse caso, usei um singleton).
Como você pode ver, o controlador de visualização raiz é o meu Controlador de guias principais . Fiz isso porque depois que o usuário faz login, quero que o aplicativo seja iniciado diretamente na primeira guia. (Isso evita qualquer "tremulação" em que a visualização de login seja exibida temporariamente.)
AppDelegate.m
Neste arquivo, verifico se o usuário já está logado. Caso contrário, pressione o controlador de exibição de login. Também lido com o processo de logout, onde apago dados e mostro a visualização de logon.
LoginViewController.m
Aqui, se o login for bem-sucedido, simplesmente rejeito a visualização e envio uma notificação.
fonte
[self.window makeKeyAndVisible]; [self.window.rootViewController presentViewController:viewController animated:animated completion:nil];
porself.window.rootViewController = viewController;
para evitar tremulações. Para animar que apenas envolvê-la em um[UIView transitionWithView...];
EDIT: Adicione ação de logout.
1. Primeiro, prepare o arquivo delegado do aplicativo
AppDelegate.h
AppDelegate.m
2. Crie uma classe chamada Usuário.
User.h
Usuário.m
3. Crie um novo controlador RootViewController e conectado à primeira visualização, onde o botão de login está ativo. Adicione também um ID do Storyboard: "initialView".
RootViewController.h
RootViewController.m
4. Crie um novo controlador LoginViewController e conectado à visualização de login.
LoginViewController.h
LoginViewController.m
5. No final, adicione um novo controlador ProfileViewController e conectado à visualização de perfil na guia ViewController.
ProfileViewController.h
ProfileViewController.m
LoginExample é um projeto de amostra para ajuda extra.
fonte
Não gostei da resposta de bhavya por usar
AppDelegate
dentro dos Controladores de exibição e a configuraçãorootViewController
não tem animação. E a resposta de Trevor tem problemas com o controlador de exibição intermitente no iOS8.UPD 18/07/2015
AppDelegate dentro dos View Controllers:
Alterar o estado AppDelegate (propriedades) dentro do controlador de exibição interrompe o encapsulamento.
Hierarquia muito simples de objetos em todos os projetos iOS:
AppDelegate (possui
window
erootViewController
)ViewController (proprietário
view
)Tudo bem que os objetos do topo alterem os objetos na parte inferior, porque os estão criando. Mas não está tudo bem se os objetos na parte inferior alteram os objetos em cima deles (descrevi alguns princípios básicos de programação / OOP: DIP (Princípio de Inversão da Dependência: o módulo de alto nível não deve depender do módulo de baixo nível, mas de abstrações) )
Se algum objeto alterar qualquer objeto nesta hierarquia, mais cedo ou mais tarde haverá uma confusão no código. Pode ser bom nos pequenos projetos, mas não é divertido vasculhar essa bagunça nos pequenos projetos =]
UPD 18/07/2015
Eu replico animações de controlador modal usando
UINavigationController
(tl; dr: verifique o projeto ).Estou usando
UINavigationController
para apresentar todos os controladores no meu aplicativo. Inicialmente, exibi o controlador de exibição de login na pilha de navegação com animação simples push / pop. Decidi alterá-lo para modal com o mínimo de alterações.Como funciona:
O controlador de exibição inicial (ou
self.window.rootViewController
) é UINavigationController com ProgressViewController como umrootViewController
. Estou mostrando o ProgressViewController porque o DataModel pode levar algum tempo para inicializar porque ele possui uma pilha de dados principal, como neste artigo (eu realmente gosto dessa abordagem).O AppDelegate é responsável por obter atualizações de status de login.
O DataModel manipula o login / logout do usuário e o AppDelegate está observando sua
userLoggedIn
propriedade via KVO. Indiscutivelmente, não é o melhor método para fazer isso, mas funciona para mim. (Por que o KVO é ruim, você pode fazer check-in neste ou neste artigo (parte Por que não usar notificações?).ModalDismissAnimator e ModalPresentAnimator são usados para personalizar a animação por push padrão.
Como a lógica dos animadores funciona:
AppDelegate se define como um delegado de
self.window.rootViewController
(que é UINavigationController).AppDelegate retorna um dos animadores,
-[AppDelegate navigationController:animationControllerForOperation:fromViewController:toViewController:]
se necessário.Animadores implementam
-transitionDuration:
e-animateTransition:
métodos.-[ModalPresentAnimator animateTransition:]
:O projeto de teste está aqui .
fonte
AppDelegate
(eu estaria interessado em entender por que você faz isso) - mas seu comentário sobre a falta de animação é muito válido. Isso pode ser resolvido por esta resposta: stackoverflow.com/questions/8053832/...UITabBarController
há muito tempo. Eu provavelmente começaria com a abordagem de janela em vez de manipular os controladores de exibição.Aqui está a minha solução Swifty para futuros espectadores.
1) Crie um protocolo para lidar com as funções de login e logout:
2) Estenda o protocolo e forneça aqui a funcionalidade para efetuar logout:
3) Em seguida, posso adaptar meu AppDelegate ao protocolo LoginFlowHandler e chamar
handleLogin
na inicialização:A partir daqui, minha extensão de protocolo manipulará a lógica ou determinará se o usuário efetuou login / logout e alterará o rootViewController do Windows de acordo!
fonte
LoginFlowHandler
. Estou esquecendo de algo? Além disso, acho que esse código apenas gerencia o logon na inicialização. Como gerencio o logout de um controlador de exibição?AppState
implementação, portanto, dependeria de como você está salvando seus dados do usuário em disco.handleLogout
funcionalidade?LoginFlowHandler
protocolo. Então você terá escopo para poder chamar o método handleLogout. Veja minha etapa 3 para um exemplo de como eu fiz isso na classe AppDelegate.Fazer isso com o delegado do aplicativo NÃO é recomendado. O AppDelegate gerencia o ciclo de vida do aplicativo relacionado ao lançamento, suspensão, encerramento e assim por diante. Sugiro fazer isso no seu controlador de exibição inicial no
viewDidAppear
. Você podeself.presentViewController
eself.dismissViewController
no controlador de visualização de login. Armazene umabool
chaveNSUserDefaults
para ver se está iniciando pela primeira vez.fonte
Depois de criar o LoginViewController e o TabBarController , precisamos adicionar um StoryboardID como " loginViewController " e " tabBarController ", respectivamente.
Então eu prefiro criar a estrutura Constant :
No LoginViewController, adicione IBAction :
No ProfileViewController, adicione IBAction :
No AppDelegate, adicione a linha de código em didFinishLaunchingWithOptions :
Por fim, crie a classe Switcher :
Isso é tudo!
fonte
No Xcode 7, você pode ter vários storyBoards. Será melhor se você puder manter o fluxo de Login em um storyboard separado.
Isso pode ser feito usando SELECT VIEWCONTROLLER> Editor> Refactor to Storyboard
E aqui está a versão Swift para definir uma exibição como o RootViewContoller-
fonte
Eu uso isso para verificar o primeiro lançamento:
(se o usuário excluir o aplicativo e reinstalá-lo, será considerado como um primeiro lançamento)
No AppDelegate, verifico o primeiro lançamento e crio um controlador de navegação com as telas de login (login e registro), que coloco no topo da janela principal atual:
Como ele está no topo do controlador de exibição comum, ele é independente do resto do seu aplicativo e você pode simplesmente ignorar o controlador de exibição, se não precisar mais dele. E você também pode apresentar a visualização dessa maneira, se o usuário pressionar um botão manualmente.
BTW: eu salvo os dados de login dos meus usuários assim:
Para o logout: mudei do CoreData (muito lento) e usei o NSArrays e o NSDictionaries para gerenciar meus dados agora. Logout significa apenas esvaziar essas matrizes e dicionários. Além disso, certifique-se de definir meus dados no viewWillAppear.
É isso aí.
fonte
Estou na mesma situação que você e a solução que encontrei para limpar os dados está excluindo todo o material CoreData em que meus controladores de exibição se baseiam para desenhar suas informações. Mas ainda achei essa abordagem muito ruim, acho que uma maneira mais elegante de fazer isso pode ser realizada sem storyboards e usando apenas código para gerenciar as transições entre os controladores de exibição.
Encontrei este projeto no Github que faz tudo isso apenas por código e é bastante fácil de entender. Eles usam um menu lateral semelhante ao Facebook e o que fazem é alterar o controlador da visualização central, dependendo se o usuário está logado ou não. Quando o usuário efetua logout,
appDelegate
remove os dados do CoreData e configura o controlador de exibição principal para a tela de login novamente.fonte
Eu tive um problema semelhante para resolver em um aplicativo e usei o seguinte método. Não usei notificações para lidar com a navegação.
Eu tenho três storyboards no aplicativo.
Meu storyboard inicial no aplicativo é o storyboard da tela Splash. Eu tenho o controlador de navegação como raiz do storyboard de login e barra de guias para lidar com as visualizações do controlador.
Eu criei uma classe Navigator para lidar com a navegação do aplicativo e fica assim:
Vejamos os cenários possíveis:
Como tenho o controlador de navegação como raiz, instancio o controlador de navegação como controlador de exibição inicial.
Isso remove o storyboard slpash da raiz da janela do aplicativo e o substitui pelo storyboard de login.
No storyboard de login, quando o usuário faz login com êxito, eu salvo os dados do usuário em Padrões do Usuário e inicializo um singleton UserData para acessar os detalhes do usuário. O storyboard da barra de guias é carregado usando o método navigator.
Agora o usuário sai da tela de configurações na barra de guias. Limpo todos os dados do usuário salvos e navego para a tela de login.
Quando o usuário inicia o aplicativo, a tela inicial é carregada. Verifico se o usuário está logado e acesso os dados do usuário em Padrões do usuário. Em seguida, inicialize o singleton UserData e mostre a barra de guias em vez da tela de login.
fonte
Graças à solução de bhavya. Houve duas respostas sobre o swift, mas essas não estão muito intactas. Eu fiz isso no swift3.Below é o código principal.
Em AppDelegate.swift
Em SignUpViewController.swift
Na função logOutAction
fonte
insira a descrição da imagem aqui
No aplicativo Delegate.m
}
ver controller.m Em vista, o carregamento
}
Ação do botão Logout
fonte
NSUserDefaults
é muito insegura para esse tipo de dados!