Configure window in App Delegate with TabBar and NavBar - xcode

I'm not totally sure how to phrase this, but for some reason I'd assume its fairly simple. The below is code that works for a NavigationBar and a ViewController to set up the managed context/core data in my App Delegate (under didFinishLaunchingWithOptions). How do I make the same thing work but with a TabBar as well (assuming I still want to get to the UIViewController)?
let navController = window!.rootViewController as! UINavigationController
let viewController = navController.topViewController as! ViewController
viewController.coreDataStack = coreDataStack
The below was my attempt at doing this, but it errors out with the "tabController.selectedIndex = 2" command.
let tabController = window!.rootViewController as! UITabBarController
let navController = (tabController.selectedIndex = 2) as! UINavigationController
let viewController = navController.topViewController as! FamilyViewController
viewController.coreDataStack = coreDataStack
Any ideas? Thanks in advance for any help!

I think let navController = (tabController.selectedIndex = 2) as! UINavigationController is not correct.
tabController.selectedIndex = 2 instead of that you should use [tabController.viewControllers objectAtIndex:2]
Sorry for not using swift syntax but I think you can get the idea from that.

Related

Cannot add viewcontroller´s frame to a scrollview in another viewcontroller

I want to add a swipe function to my app and swipe between viewcontrollers as in this tutorial: https://www.youtube.com/watch?v=3jAlg5BnYUU
The source code for the tutorial is here: https://www.veasoftware.com/posts/swipe-navigation-in-swift-xcode-7-ios-9-tutorial
In that guide they are using nib/xib files that they create together with the corresponding viewcontrollers that they then use to call for in their ViewController´s constructors.
I have done exact the same and it is wokring as in the tutorial. But I also want use a ViewController that not has a xib file because it is on my storyboard. That viewcontroller is called ViewController2 in my code below and it is the only that does not appear in the scrollview when I swipe. The other two do because I call for the xibName in the constructor call but ViewController2 does not have a xib file since it is on my storyboard.
So how can I add it to the scrollview so it appears when I swipe?
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let vc0 = ViewController0(nibName: "ViewController0", bundle: nil)
self.addChildViewController(vc0)
self.scrollView.addSubview(vc0.view)
vc0.didMoveToParentViewController(self)
let vc1 = ViewController1(nibName: "ViewController1", bundle: nil)
var frame1 = vc1.view.frame
frame1.origin.x = self.view.frame.size.width
vc1.view.frame = frame1
self.addChildViewController(vc1)
self.scrollView.addSubview(vc1.view)
vc1.didMoveToParentViewController(self)
let vc2 = ViewController2()
var frame2 = vc2.view.frame
frame2.origin.x = self.view.frame.size.width
vc2.view.frame = frame2
self.addChildViewController(vc2)
self.scrollView.addSubview(vc2.view)
vc2.didMoveToParentViewController(self)
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 3, self.view.frame.size.height - 66);
}
Try doing the following:
1) Getting the storyboard object programmatically.
2) Giving the View Controller 2 in your storyboard file a storyboard ID. You can do this by going to your Main.storyboard file and selecting the view controller you wish to give an identifier and then looking in the Identity Inspector (It should be in the under "Identity" section.
3) Instantiating an instance of View Controller 2 with the storyboard method instantiateViewControllerWithIdentifier. This method uses a storyboard ID as it's argument and adding that as the child of your scroll view.
Like so:
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
//1
let mainStoryboard = UIStoryboard.init(name: "Main", bundle: NSBundle.mainBundle())
//3
let vc2 = mainStoryboard.instantiateViewControllerWithIdentifier("<InsertStoryBoardID>") as! ViewController2
self.addChildViewController(vc2)
self.scrollView.addSubview(vc2.view)
vc2.didMoveToParentViewController(self)
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 3, self.view.frame.size.height - 66);
}
Hope this helps! Feel free to ask questions!

App opens to specific ViewController inside Navigation Controller

I'm trying to have my app open to a specific ViewController that is deeply embedded in a Navigation Controller, but isn't the RootViewController. I have tried in the app delegate didFinishLaunchingWithOptions adding:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("NavViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
But this goes to the root view controller. I tried changing this line to:
storyboard.instantiateViewControllerWithIdentifier("MainViewController")
and this does open to the correct viewcontroller but then there is no Navigation Bar on the top which is needed to navigate in the app.
To access the rootViewController from the AppDelegate then here is the code:
let rootViewController = application.windows[0].rootViewController as! UINavigationController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let notificationVC = mainStoryboard.instantiateViewControllerWithIdentifier("identifier") as! NotificationVC
rootViewController.pushViewController(notificationVC, animated: false)
Now, it will have the navigationBar. Let me know, if you still face the issue. thanks.
Here is the Objective-C version to open a specific UIViewController deeply embedded inside a UINavigationController (which is not the rootController).
If we take #bdc example in comments and we want to open UIViewController D:
A : rootViewController
N : navigationController
B, C, D : UIViewControllers embedded in N
A -> N[B C D]
Set storyboardId in InterfaceBuilder for every UIViewController or UINavigationController in the hierarchy through D.
In AppDelegate, the code is straight forward. You just have to instantiate everything, and use your UINavigationController to push every UIViewController in your hierarchy.
// Instanciate from storyboard with identifiers
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
UINavigationController * N = (UINavigationController*) [storyboard instantiateViewControllerWithIdentifier:#"N"];
UIViewController* B = (UIViewController*) [storyboard instantiateViewControllerWithIdentifier:#"B"];
UIViewController* C = (UIViewController*) [storyboard instantiateViewControllerWithIdentifier:#"C"];
UIViewController* D = (UIViewController*) [storyboard instantiateViewControllerWithIdentifier:#"D"];
// Set up the views hierarchy
self.window.rootViewController = N;
[N pushViewController:B animated:NO];
[N pushViewController:C animated:NO];
[N pushViewController:D animated:YES];
[self.window makeKeyAndVisible];
Hope this will help.

Could not cast value of type 'UINavigationController'

I am implementing a search interface for my application, so basically I will pass the search keyword from one ViewController to another ViewController.
I have done this type of parameter passing several times but something seems strange this time. The destination ViewController is embedded in a Navigation Controller.
Now the code looks something like this.
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject!) {
if (segue?.identifier == "home_to_search") {
var searchKeyword = txtSearchBarHome.text
var svc = segue?.destinationViewController as! SearchViewController;
svc.toPassSearchKeyword = searchKeyword;
//let nav = segue?.destinationViewController as! UINavigationController
//let svc = nav.topViewController as! SearchViewController
//svc.toPassSearchKeyword = searchKeyword;
}
}
I have already explored these questions
DestinationViewController Segue and UINavigationController swift, How do I segue values when my ViewController is embedded in an UINavigationController? with no luck.
What makes me wonder is that I already have ViewControllers embedded in Navigation Controllers that I can pass parameters by segueing. However, in this case it throws a Could not cast value of type 'UINavigationController' error. If I try the commented code above it does not throw an error there, but at the AppDelegate class.
Answering my own question. In this case we need to access the child view by doing something like this:
let nav = segue?.destinationViewController as! UINavigationController
let svc = nav.topViewController as! SearchViewController
svc.toPassSearchKeyword = searchKeyword;
Based on Semih's answer, you can also do this to pass a variable to next segue if you don't want to use an identifier:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let nav = segue.destination as? UINavigationController,
let vc = nav.topViewController as? TestViewController {
vc.username = "Test"
}
}
Just a quick note for those looking into this issue it has been renamed to Destination
let nav = segue.destination as! UINavigationController
let svc = nav.topViewController as! SearchViewController
svc.toPassSearchKeyword = searchKeyword;

cocoa - Edit/Design NSView visually

How can I visually design a NSView in Xcode? I'm trying to build a statusBar app with a statusMenu only
As you can see above, the object appear but I can't edit it visually, then it go like this as a result:
I attempted to use a XIB file (only have a NSView, no ViewController), but I can't put the NSView in the XIB into the AppDelegate. I tried another ways and managed to use the XIB file, but then I can't use the Storyboard.
Do you have any idea for this situation?
UPDATE
Thank Max for answer my question. I actually tried that before but failed. I tried it again after your comment and there's still no luck. Here is how I did
I created a ViewController then I change its view to the MenuCustomView (NSView)
This is the code in AppDelegate
let statusBar = NSStatusBar.systemStatusBar().statusItemWithLength(-1)
var menuCustomView = NSView()
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
let statusIcon = NSImage(named: "statusIcon")
let statusMenu = NSMenu()
statusBar.image = statusIcon
statusBar.menu = statusMenu
let menuItem = NSMenuItem()
menuItem.title = "title"
var vc = ViewController()
menuCustomView = vc.view
menuItem.view = menuCustomView
statusMenu.addItem(menuItem)
}
Files I have in the project
Even though you don't need the view controller, you can use them to design the views. Create one in the storyboard, edit the view the way you want.
Then you can use the view by creating a viewController out of the storyboard and using its view property to attach the view to the NSStatusBarItem
My words in code:
let storyboard = NSStoryboard(name: "Main", bundle: nil)
let viewController = storyboard?.instantiateControllerWithIdentifier("MyViewController") as! NSViewController
let view = viewController.view
I assume you want to add functioning code to the view. To, for example respond to the button click, you have to subclass the NSViewController and then implement the code you would have added to the AppDelegate.
If you need any more explanation, feel free to write me :)

How to present a modal atop the current view in Swift

(Xcode6, iOS8, Swift, iPad)
I am trying to create a classic Web-like modal view, where the outside of the dialog box is "grayed-out." To accomplish this, I've set the alpha value of the backgroundColor of the view for the modal to 0.5, like so:
self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
The only problem is that when the modal becomes full-screen, the presenting view is removed. (Ref Transparent Modal View on Navigation Controller).
(A bit irritated at the concept here. Why remove the underlying view? A modal is, by definition, to appear atop other content. Once the underlying view is removed, it's not really a modal anymore. it's somewhere between a modal and a push transition. Wa wa wa... Anyway..)
To prevent this from happening, I've set the modalPresentationStyle to CurrentContext in the viewDidLoad method of the parent controller, and in Storyboard... but no luck.
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
How do I prevent the presenting view from being removed when the modal becomes full screen?
tyvm.. more info below.
Also in Storyboard, like so (Presentation: Current Context)
Thx for your help... documentation below:
First, remove all explicit setting of modal presentation style in code and do the following:
In the storyboard set the ModalViewController's modalPresentation style to Over Current context
Check the checkboxes in the Root/Presenting ViewController - Provide Context and Define Context.
They seem to be working even unchecked.
You can try this code for Swift:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
let navigationController = UINavigationController(rootViewController: popup)
navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(navigationController, animated: true, completion: nil)
For swift 4 latest syntax using extension:
extension UIViewController {
func presentOnRoot(`with` viewController : UIViewController){
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(navigationController, animated: false, completion: nil)
}
}
How to use:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
self.presentOnRoot(with: popup)
The only problem I can see in your code is that you are using CurrentContext instead of OverCurrentContext.
So, replace this:
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
for this:
self.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
This worked for me in Swift 5.0. Set the Storyboard Id in the identity inspector as "destinationVC".
#IBAction func buttonTapped(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let destVC = storyboard.instantiateViewController(withIdentifier: "destinationVC") as! MyViewController
destVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
destVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(destVC, animated: true, completion: nil)
}
The problem with setting the modalPresentationStyle from code was that you should have set it in the init() method of the presented view controller, not the parent view controller.
From UIKit docs: "Defines the transition style that will be used for this view controller when it is presented modally. Set
this property on the view controller to be presented, not the presenter. Defaults to
UIModalTransitionStyleCoverVertical."
The viewDidLoad method will only be called after you already presented the view controller.
The second problem was that you should use UIModalPresentationStyle.overCurrentContext.
The only way I able to get this to work was by doing this on the presenting view controller:
func didTapButton() {
self.definesPresentationContext = true
self.modalTransitionStyle = .crossDissolve
let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
let navController = UINavigationController(rootViewController: yourVC)
navController.modalPresentationStyle = .overCurrentContext
navController.modalTransitionStyle = .crossDissolve
self.present(navController, animated: true, completion: nil)
}
I am updating a simple solution. First add an id to your segue which presents modal. Than in properties change it's presentation style to "Over Current Context". Than add this code in presenting view controller (The controller which is presenting modal).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8
if((segue.identifier == "chatTable")){
if (iOS8){
}
else {
self.navigationController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
}
}
}
Make sure you change segue.identifier to your own id ;)

Resources