UISplitViewController Start with Master View instead of detailView - ios

app is starting in detailViewController instead of MasterViewController.
how to fix that in the iPhone?
(its a universal app, and don't want changes when it runs in the iPad)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "embedseg" {
guard let splitViewController = segue.destination as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let rightNavController = splitViewController.viewControllers.last as? UINavigationController,
let detailViewController = rightNavController.topViewController as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstmonster
masterViewController.delegate = detailViewController
detailViewController.navigationItem.leftItemsSupplementBackButton = true
detailViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}
}

Related

iOS Swift - implementation of SplitViewController inside a Container View

I'm following this tutorial link
But with one change that I made since the beginning.
I Added a ViewController (and made it the Initial View Controller) and Added a Container View in it.
Then I embed seagued between my View Container and the tutorial's SplitViewController.
And all worked well, until I got to this step:
Go to to AppDelegate.swift and replace the implementation of application(_:didFinishLaunchingWithOptions:) with the following:
guard let splitViewController = window?.rootViewController as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let detailViewController = splitViewController.viewControllers.last as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
return true
How this code should be modified to work with my case?
In your case you can't get access to uisplitviewcontroller in AppDelegate. Since you are using Container Embedded view like in image below. You get reference of the UISplitviewcontroller from prepareFor segue of your first viewController. So instead of writing code in AppDelegate, try do that in prepare for segue in your initial viewController.
Initial ViewController
class ViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "embedseg" {
guard let splitViewController = segue.destination as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let rightNavController = splitViewController.viewControllers.last as? UINavigationController,
let detailViewController = rightNavController.topViewController as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
masterViewController.delegate = detailViewController
detailViewController.navigationItem.leftItemsSupplementBackButton = true
detailViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}
}
}

Pass Information through TabBarController Swift

Have a Table View Controller that will pass an ID field onto a View Controller in order to retrieve detail however in between the two controllers is a Tab Bar Controller. I am unsure how I am to get the information passed between the two. Was attempting to use a Segue but the value is blank once it gets to the detail controller.
EventBarTableViewCell.swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showEventDetail" {
if let IndexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as? eventDetailViewController
controller?.inTradeShowID = (events?[IndexPath.row].tradeshowID!)!
controller?.viaSegue = (events?[IndexPath.row].tradeshowID!)!
//controller?.performSegue(withIdentifier: "tradeShowID", sender: self)
//if shouldShowSearchResults {
// controller?.viaSegue = filteredArray[IndexPath.row].charterNum!
//} else {
// controller?.viaSegue = repositories[IndexPath.row].charterNum!
//}
}
}
}
eventDetailViewController.swift
var viaSegue = ""
var inTradeShowID = ""
override func viewDidLoad() {
super.viewDidLoad()
inTradeShowID = self.viaSegue
}
Could use some help.
You are segueing to a Tab Bar Controller, not to your "display" view, so you need to "drill down" so to speak:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showEventDetail" {
if let IndexPath = self.tableView.indexPathForSelectedRow {
// we're segueing to a Tab Bar Controller
if let tabBarVC = segue.destination as? UITabBarController {
// get the first view controller of the Tab Bar Controller
// *that* is where you want to "pass" your data
if let controller = tabBarVC.viewControllers?.first as? eventDetailViewController {
// either should work
controller.inTradeShowID = (events?[IndexPath.row].tradeshowID!)!
controller.viaSegue = (events?[IndexPath.row].tradeshowID!)!
} //end if let controller = tabBarVC.viewControllers?.first as? eventDetailViewController
} //end if let tabBarVC = segue.destination as? UITabBarController
} //end if let IndexPath = self.tableView.indexPathForSelectedRow
} //end if segue.identifier == "showEventDetail"
}

Controlling Nav Controller from another

My view controllers are sitting inside of view containers.
I'm trying to change the nav controller in the green area with the buttons from the purple area.
In my Main View controller I have:
class MainViewController: UIViewController,Purpleprotocol,Greenprotocol {
weak var infoNav : UINavigationController?
weak var greenVC: GreenVC?
weak var purpleVC: PurpleVC?
weak var peachVC: PeachVC?
func changenav(whichbutton: String) {
print ("changenav")
print(whichbutton + "whichbuttonstring")
if(whichbutton == "1"){
print("change one")
let svc = storyboard?.instantiateViewController(withIdentifier: "rootController") as! GreenVC
self.infoNav?.pushViewController(svc, animated: true)
}
if(whichbutton == "2"){
print("change two")
let svc = storyboard?.instantiateViewController(withIdentifier: "secondController") as! SecondViewController
self.infoNav?.pushViewController(svc, animated: true)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "contentSegue" {
print("contentSegue")
let infoNav = segue.destination as! UINavigationController
let greenVC = infoNav.viewControllers[0] as! GreenVC
greenVC.delegate = self
}
if segue.identifier == "menuSegue" {
let dvmenu = segue.destination as! PurpleVC
purpleVC = dvmenu
dvmenu.delegate = self
}
}
This function does work and I can see the "change one" etc being called but the navigation controller is just not changing..not sure how to get to it I guess correctly.

Could not cast value of type 'Authorize.ClubsViewController' (0x109c70cc8) to 'Authorize.NewViewController' (0x109c70df8)

#IBOutlet weak var menuButton: UIButton!
#IBOutlet weak var clubButton: UIButton!
#IBOutlet weak var announcemnetsButton: UIButton!
#IBOutlet weak var eventButton: UIButton!
let transition = CircularTransition()
override func viewDidLoad() {
super.viewDidLoad()
menuButton.layer.cornerRadius = menuButton.frame.size.width / 2
clubButton.layer.cornerRadius = menuButton.frame.size.width / 2
announcemnetsButton.layer.cornerRadius = menuButton.frame.size.width / 2
eventButton.layer.cornerRadius = menuButton.frame.size.width / 2
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondVC = segue.destination as! NewViewController
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
let thirdVC = segue.destination as! ClubsViewController
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
let fourthVC = segue.destination as! AnnouncementsViewController
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
let fifthVC = segue.destination as! EventsViewController
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
I am running this code but I keep getting the error, what am I doing wrong? I believe everything is linked correctly, but I keep getting the SIGABRT error.
Every Segue has a identifier. You have to set identifier for segue
In the prepare you are not checking the segue identifier. Due to that you are trying to forcefully convert the segue.destination controller four different controller, which is wrong.
Please see how to set segue identifier
And change your code based on your segue identifier
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "NewVC" {
let secondVC = segue.destination as! NewViewController
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
} else if segue.identifier == "ClubVC" {
let thirdVC = segue.destination as! ClubsViewController
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
} else if segue.identifier == "AnnouncementVC" {
let fourthVC = segue.destination as! AnnouncementsViewController
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
} else if segue.identifier == "EventVC" {
let fifthVC = segue.destination as! EventsViewController
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
}
You seem to be converting the same segue destination to many different types of VC which it obviously cannot be all at the same time.
I think what you intended to do is to check if the segue destination is of the specific type (in which case you must not force-unwrap with !):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondVC = segue.destination as? NewViewController {
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
} else if let thirdVC = segue.destination as? ClubsViewController {
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
} else if let fourthVC = segue.destination as? AnnouncementsViewController {
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
} else if let fifthVC = segue.destination as? EventsViewController {
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
}
Using segue identifiers though could be more sensible in this situation.
Then again, considering that you are always performing the same actions no matter what VC that is, maybe it's worth casting it to a generic VC (i.e. as! UIViewController and performing an action on that instead of differentiating them?

Pass text to TextView via Segue

I'm trying to pass text to TextView from other ViewController:
if (segue.identifier == "HomeToDetails") {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
nextVC.infoTextView.text = "TESTING"
}
But it crashes:
fatal error: unexpectedly found nil while unwrapping an Optional value
setting text on UITextField of DestinationViewController is not possible in the prepareForSegue:sender, because all view components of the recently allocated controller are not initialized before the view is loaded (at this time, they are all nil), they only will be when the DestinationViewController view is loaded.
You need to use optional variable infoString in DetailsViewController which you can set in prepareForSegue method
if (segue.identifier == "HomeToDetails") {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
nextVC.infoString = "TESTING"
}
in DetailsViewController.swift
class DetailViewController: UIViewController {
var infoString: String?
override func viewDidLoad() {
super.viewDidLoad()
if let info = infoString {
self.infoTextView.text = info
}
}
}
if value is nil and you unwrap it, then the app will crash, you should use optional binding to avoid crash.
if (segue.identifier == "HomeToDetails") {
if let nav = segue.destination as? UINavigationController { //should use optional binding to avoid crash
if let nextVC = nav.topViewController as? DetailsViewController {
nextVC.infoTextView.text = "TESTING"
}
}
}
Check this:
if (segue.identifier == "HomeToDetails") {
// get a reference to the second view controller
let secondViewController = segue.destination as! DetailsViewController
// set a variable in the second view controller with the String to pass
secondViewController.infoTextView.text = "TESTING"
}
Try this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let nav = segue.destination as? UINavigationController {
if let nextVC = nav.topViewController as? DetailsViewController {
nextVC.infoTextView.text = "Data you want to pass"
}
}
}
this is because when you are assigning value to text view, the text view not initialized that time as viewDidLoad of next class is not called yet. So pass only string, then in viewDidLoad of next class, set the text.
You cannot pass a text directly to TextView in another view before it's created.
First ViewController:
if (segue.identifier == "HomeToDetails") {
let secondViewController = segue.destination as! DetailsViewController
secondViewController.myText = "TESTING"
}
DetailsViewController:
var myText = ""
override func viewDidLoad() {
super.viewDidLoad()
infoTextView.text = myText
}
All view components of the DetailsViewController are not initialized before the view is loaded. You can load that view before assigning values to the components of that view
Consider vC is the view controller which contains the view that you want to load. Then
if let _ = vC.view {
//Assign value here
}
Once the view is loaded, we can set the value to the components in that view. In SWIFT 3
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "HomeToDetails" {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
if let _ = nextVC.view {
nextVC.infoTextView.text = "TESTING"
}
}
}

Resources