Change first viewController presented (main interface) - ios

Hello i have done a page controller for my app.
This page controller will appear at the app launch if there isn't any "User" core data object on the device.
So want i want to do is :
When app launch, do a core data request that return all "User" objects in a array. (this part is ok)
If the array is empty the VC presented is the pageController else that's the normal on whose presented.
The pageController and the other controller are on different storyboards.
I have seen we can change the first storyboard in the app parameter, that's parameter is called main interface.
Actually main interface is the normal VC, so how can i present the page controller programmaticly in my didFinishLaunchingWithOptions() when my condition is true ?

Inside didFinishLaunchingWithOptions
// query coredata
if arr.isEmpty {
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "pageID") as! PageController
self.window?.rootViewController = viewController
}
else {
let otherController = UIStoryboard(name: "Other", bundle: nil).instantiateViewController(withIdentifier: "otherID") as! OtherController
self.window?.rootViewController = otherController
}

Related

passing data from 2 view controllers without segue

I have a mainviewcontroller and a popup view controller which opens without a segue.
the popup viewcontroller recive data from Firebase, and then i need to append this data to an array in the mainviewcontroller.
How can i do that?
(i tried to create a property of the popupviewcontroller in the mainviewcontroller, but in crashes the app)
this is the code that opens the popup:
#IBAction func showPopUp(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUp") as! PopUpViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
You need to connect the classes so that the popup class knows what to do with the data once it has been received. Here's a sample structure that works in a playground that you should be able to apply to your real classes.
class MainClass {
func showPopUp() {
let popOverVC = PopUpClass()
popOverVC.update = addToArray
popOverVC.receivedData()
}
func addToArray() {
print("Adding")
}
}
class PopUpClass {
var update: (()->())?
func receivedData() {
if let updateFunction = update {
updateFunction()
}
}
}
let main = MainClass()
main.showPopUp()
Or you could create a global variable so it can be accessed anywhere. ... It is better to pass data but I just thought it would be easier in this instance, so the variable can be accessed anywhere in your entire project.
if it is just a notification, you can show it in an alert, but if you don't want to use an alert my offer to present another view controller is not like this , try my code :
//if you have navigation controller ->
let vc = self.storyboard?.instantiateViewController(
withIdentifier: "storyboadrID") as! yourViewController
self.navigationController?.pushViewController(vc, animated: true)
//if you don't use navigation controller ->
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "storyboadrID") as! yourViewController
self.present(VC1, animated:true, completion: nil)
also if you want to pass any data or parameter to destination view controller you can put it like this before presenting your view controller :
VC1.textView.text = "test"

How to obtain reference to a View Controller from UITabBarViewController

EDIT: I was off base in my approach. I'm trying to pass data from one VC to another. The source VC is not controlled by a Tab Bar, so I can't reference the destination VC through it. I am attempting to reference the destination VC thorough the Storyboard, but the data is still nil on the destination VC. I'm using Core Data and wish to pass the ManagedObjectContext to another VC. Here is the code:
......
do {
try self.managedObjectContext.save()
appUserID = user.userID!
} catch {
fatalError("Error: \(error)")
}
}
}
self.passManagedObjectContext()
}
func passManagedObjectContext() {
let profileTableViewController = UIStoryboard(name: "Profile", bundle: nil).instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileTableViewController
profileTableViewController.managedObjectContext = self.managedObjectContext
}
I am passing data from the AppDelegate to other ViewControllers by referencing my TabBarViewControllers stack like so:
let tabBarController = window!.rootViewController as! UITabBarController
if let tabBarViewControllers = tabBarController.viewControllers {
let profileNavController = tabBarViewControllers[4] as! UINavigationController
let profileTableViewController = profileNavController.topViewController as! ProfileTableViewController
profileTableViewController.managedObjectContext = context
}
}
.....
END EDIT
I'm trying to do the same now but from one ViewController to another that is accessed through the tab bar (no segue). The code above does not recognize window!.rootViewController how can I reference the root UITabBarController?
UIViewController has a built-in optional property tabBarController, so inside your view controller you can access the tabBarController like so:
if let tabBarController = tabBarController {
//get the controller you need from
//tabBarController.viewControllers
//and do whatever you need
}
Here is the current list of properties available in the 'Getting Other Related View Controllers' section of Apple's UIViewController documentation:

Setting Init VC in App Delegate?

I am trying to init my core data stack with the init VC of my app. To do this I want to pass the core data manager i have created into the first VC upon loading.
I thought this code would make sense to pass the coredatamanager into the VC, however I get errors whichever way i write this code, im sure im missing something simple?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "RoutineController", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? ViewController {
// Configure View Controller
viewController.coreDataManager = coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
}
Error is simply:
Use of undeclared type 'ViewController'
However if i delete 'as? ViewController' I get an error on the following line that viewController has no property coreDataManager.
Is there some sort of delegate i need to define in the viewdidload of the view controller in sending to?
EDIT Revised my code to correct the storyboard ID, however the code inside the {} doesnt seem to execute, i get the printed error i wrote due to the if let failing, so this still isnt the right way to set the viewController...any ideas as to why?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? RoutineController {
// Configure View Controller
print("SENDING THIS INFO TO THE FIRST VC \(self.coreDataManager)")
viewController.coreDataManager = self.coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
} else {
print("WE COULDNT SET VIEWCONTROLLER AS THE DESIGNATED VC SO MOC WASNT PASSED")
}
This is your problem:
as? ViewController
should be
as! UIViewController
alternatively this should also work:
as! RoutineController
Select the RoutineController in your storyboard and set the storyboard ID
Then use the Storyboard ID here:
if let viewController = storyboard.instantiateViewController(withIdentifier: "<storyboardID>") as? RoutineController {
The solution was that you need to define an identifier in the if let viewController to find it successfully, the working code is as follows:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let viewController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as? TabBarController {
viewController.coreDataManager = self.coreDataManager
window?.rootViewController = viewController

How to reopen application after login

I'm an android developer. in android, when user login in application, I will re-open the MainActivity class ( controller ) to refresh some views.
in iOS applications, how to do this scenario ?
You can reopen you default/LandingViewController.
Suppose you have a View Controller with name LandingViewController
When you successfully logged in all you need is to re instantiate the LandingViewController
In AppDelegate class make a function with name
func userDidLoggedIn(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)//Replace Main With your own storyboard name containing LandingViewController
let landingViewController = storyboard.instantiateViewController(withIdentifier: "LandingViewControllerIdentifier")//Pass your LandingViewController Identier that you have set in your storyboard file.
guard let subviews = self.window?.subviews else {
return
}
for view in subviews {
view.removeFromSuperview()
}
self.window?.rootViewController = landingViewController
}
Now Simply Call this Function where ever in the entire project like this In your case write below lines in the completion block of login request API.
let delegate = UIApplication.shared.delegate as! AppDelegate
delegate. userDidLoggedIn()
Once user login, you can change your rootviewcontroller like this:
var nav_VC: UIViewController?
func onSuccessfulLogin()
{
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
nav_VC = nil
if nav_VC == nil {
nav_VC = storyboard.instantiateViewController(withIdentifier: "home_nav")
}
self.window?.rootViewController = nav_VC
self.window?.makeKeyAndVisible()
}

How to present different view controllers from appdelegate in ios

Actually I am having navigationcontroller as root controller it is embed in main.storyboard,i am having two screens one screen login and another one home as per login credentials i need to skip login screen and i need to show home screen.From appdelegate i am doing this skipping it is not working properly
Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x7fadf384c600>.
let storyboard=UIStoryboard.init(name: "Main", bundle: nil)
let navigationController=storyboard.instantiateInitialViewController()
let username=UserDefaultUtil.getString(key: AppConstants.PREF_USERID)
print(username!)
if username != ""
{
window?.rootViewController=navigationController
let sectionController=SectionController(nibName: "SectionController" , bundle: nil)
navigationController?.present(sectionController, animated: true, completion: nil)
}
I guess you are trying to present your sectionController in navigationController, its not really how it works, try this code:
let navigationController = self.storyboard?.instantiateInitialViewController() as! UINavigationController
and replace the present with this:
navigationController.setViewControllers([sectionController], animated: false)
or just drop the navigationController instantiate and create it with code and set it as window?.rootViewController:
let sectionController=SectionController(nibName: "SectionController" , bundle: nil)
let nav = UINavigationController(rootViewController: sectionController)
window?.rootViewController = nav
First, check the user credentials in the login page. Then use:
if hasCredentials {
let vc:AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "someViewController")
self.show(vc as! UIViewController, sender: vc)
}
Sidenote: Personally, I do this from the login page because it simplifies the process and I do not like having weight sitting in my AppDelegate. If you were thinking you did not want people seeing your login screen who are already members, you can do it from an AppDelegate, but take into account the user experience might be diminished during the loading process if this is the route you decide to take.

Resources