Show sheet when the main window first loads - macos

I am trying to get a sheet to load when the main window first loads.
This sheet is so that it asks the user for a file so that they are sort of forced to open a file for use in the program when they first start.
I tried to put performSegue(withIdentifier: sender:) in viewDidLoad(), however it just loads the sheet and nothing else.
override func viewDidLoad() {
super.viewDidLoad()
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "browse"), sender: self)
}
I want the main window to load, then the sheet to slide down immediately after asking the user to open a file.
Where should I put the performSegue or is there another way I should be doing this?

#mschmidt is right, I believe; you'll need to perform the segue from viewDidAppear() or windowDidBecomeMain() or similar; the view needs to have been displayed before you can segue from it.
Note that viewDidAppear() will fire when the view is drawn, whether or not it has focus; windowDidBecomeMain() will only fire when your app becomes the frontmost app; you may be working in another app but still be able to see your app's windows on-screen, and in this state windowDidBecomeMain() may not have fired yet.
And yes, both viewDidAppear() and windowDidBecomeMain() will fire every time the view appears or the window becomes main, meaning if you minimise the app then un-minimise it, both will fire again. So you'll need some way of ensuring your segue doesn't show again each time, unless you want it to. A simple boolean flag eg segueHasShown should achieve that.

Related

Why is my view loading but not displaying with segue?

I have a bunch of views (5) and a navigation controller the user can go through by pressing buttons that segue to the next view (each view has something the user does and sends data to the next one). My app is connected with a Firebase database, so I'm doing some stuff with that.
Anyway, the view I can't get to work is a TableViewController which works as a checklist, the user must select a certain number of cells, then clicks next and an array is sent through the prepareForSegue to the next view and this view should be display. It isn't. I have some code and some prints in the viewDidLoad that let met know that the view is supposedly loading, just not being displayed.
The screen freezes and the button just remains pressed. It doesn't crash, just stops.
My code has nothing special. It just has a performSegue in the first view and nothing really in the second one.
This is the way they're set up:
https://imgur.com/a/cyO47Pl
I've been told the problem is that there are too many push segues or something like that, could it be?

tvOS: A way to have UISearchController not appear as a button?

This code
var searchController: UISearchController!
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
view.addSubview(searchController.searchBar)
getItems()
}
produces this:
Screeshot1
Note that the searchBar appears as a button stuck in the upper left (because this is a tabbed app it appears under the tab bar when first presented. The "Button" button is there to receive focus for testing).
This is how it looks after pressing the button: Screenshot2
The second image shows how I would like things to look when the search tab opens, and the way I though it was supposed to look in tvOS.
How do I get the searchController to appear as it does in the second screenshot? Many tvOS apps do this, so I know it must be possible. I have been over the documentation carefully, but I must have missed something.
A related is issue is that the collectionView below won't take focus from the searchController. One has to go back using the remote menu button to get the collectionView to focus.
How can I get the searchController to appear as it does in the second screenshot when the view appears?
How can I get the collectionView to take focus from the searchController without having to go back to the tab bar?
is I finally ran across this passage in the tvOS developer library
All of the iOS first responder mechanisms work on tvOS. This allows
developers to present a UI, visible or hidden, and then make one of
the text fields the first responder by calling the
becomeFirstResponder method on it. This action causes the text field
to put up the keyboard UI without the user having to navigate to a
text field and click on it.
so, adding
searchController.searchBar.becomeFirstResponder()
displays the inline keyboard that I wanted users to start with. However, one has to press the menu button on the remote before the focus engine kicks in again. The menu button also dismisses the keyboard and searchBar returns to its button state.
This an answer to the first of my questions. Still clueless about the second.

Xcode: Button back to Main Menu that clears all ViewControllers?

I am new to this and I do not understand coding at all, can someone please explain in a very simple way how to fix this?
How do I "go back" from a modal segue that will clear the stack of ViewControllers that are built up from navigating around a sub menu? Currently I have a segue to a sub-menu that has a back button that segue's to the Main Menu. However I ran into memory problems and I need to do it right.
I don't actually have any code in this app, I just have a menu and sub menus that lead to more VC's with images (over 75 images in total). I need the stack of VC's to be cleared from the memory when I go from Sub-menu to Main Menu. I will keep the "back" modal segue from the images to the sub-menu because there are multiple interactions between VC's without going back to the sub menu. So I just need the VC stacks to clear going from the sub menu to main menu. I can link simple code into the back button that is already there but I don't know what I actually need to code to undo the segue and delete the VC's from memory.
Will an unwind segue from sub-menu to main menu delete the VC stack to prevent termination due to memory issues?
Example: http://i.imgur.com/LX8CaFX.png
Edit: I tried using this Dismiss Segue (http://jeffreysambells.com/2014/02/19/dismissing-a-modal-view-using-a-storyboard-segue) however if I switch between image 1 and image 2 then go back to the submenu the Dismiss Segue to the main menu actually sends me back to image 2 and then I get stuck in the sub menu.
I spent hours trying to get this to work and I have no idea, I just want a button that will clear all ViewControllers and get back to main menu.
To clear a view, have an action item (such as a button) on the screen to dismiss. Right-click (or control-click) from the button to the View Controller (the blue thing next to the First Responder button). There will be an IBAction dismissView: (or something similar) under the normal options. That will allow you to close the current view and return to the previous view.
Turns out I'm stupid.
Anyways, it's still a very similar process in iOS. There is an "exit" button on the right of the First Responder…create a subclass of UIViewController (or just do all this in your existing subclass if you already have). Create a new IBAction method in the subclass called return:
ViewController.h
//All of this, if not otherwise noted, is default code upon creating new UIViewController class.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
//Begin "custom" code
-(IBAction)returned:(UIStoryboardSegue *)segue;
//End "custom" code
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
//Begin "custom" code
-(IBAction)returned:(UIStoryboardSegue *)segue {
}
//End "custom" code
#end
You do not need to put anything inside the method. There will be an "unwind" method in the exit button (return:) if you link it now. Bingo!
I am certain there must be a better way to do this, but it works well enough (At least from what I could tell.
(I'm very sorry for telling you the wrong information!)
Edit: It can also be any name; however the argument must be a UIStoryboardSegue pointer. The method must also be in the parent's class. (e.g. First -> Second -> Third means Third exits with secondReturn: and Second exits with firstReturn:; anything else e.g. Third returning with firstReturn: will be nonfunctional in this example)

Interface Builder: determine which element has the initial focus

I have a Cocoa app with a table view and a few other controls. When the app launches and the window is shown, a blue focus ring is drawn around the table view.
How can I get rid of that focus ring? I'd like nothing to have the focus when the window first shows.
The window has initialFirstResponder binding that shows which control will be active when the window becomes active. Change the initialFirstResponder or adjust tableview settings in interface builder to hide the focus ring
The best way I've found of stopping any of the controls from being the first responder when a window is first displayed is in the window controller:
Swift 3:
class YourWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
// Wait a frame before setting the first responder to be the window itself.
// We can't just set it right now, because if the first responder is set
// to the window now the system just interprets that as meaning that we
// want the default behavior where it automatically selects a view to be
// the first responder.
DispatchQueue.main.async {
window!.makeFirstResponder(nil)
}
}
}
It's messy, and sometimes when the window loads you see the focus ring starting to appear on one of the controls for one frame, but I haven't found a better way yet.

MacRuby + Interface Builder: How to display, then close, then display a window again

I'm a complete n00b with MacRuby and Cocoa, so keep that in mind when answering - I need lots of details and explanation. :)
I've set up a simple project that has 2 windows in it, both of which are built with Interface Builder. The first window is a simple list of accounts using a table view. It has a "+" button below the table. When I click the + button, I want to show an "Add New Account" window.
I also have an AccountsController < NSWindowController and a AddNewAccountController < NSWindowController class, set up as the delegates for these windows, with the appropriate button click methods wired up, and outlets to reference the needed windows.
When I click the "+" button in the Accounts window, I have this code fire:
#add_account.center
#add_account.display
#add_account.makeKeyAndOrderFront(nil)
#add_account.orderFrontRegardless
this works great the first time I click the + button. Everything shows up, I'm able to enter my data and have it bind to my model. however, when I close the add new account form, things start going bad.
if I set the add new account window to release on close, then the second time I click the + button, the window will still pop up but it's frozen. i can't click any buttons, enter any data, or even close the form. i assume this is because the form's code has been released, so there is no message loop processing the form... but i'm not entirely sure about this.
if i set the add new account window to not release on close, then the second time i click the + button, the window shows up fine and it is usable - but it still has all the data that i had previously entered... it's still bound to my previous Account class instance.
what am I doing wrong? what's the correct way to create a new instance of the Add New Account form, create a new Account model, bind that model to the form and show the form, when I click the + button on the Accounts form?
... this is all being done on OSX 10.6.6, 64bit, with XCode 3.2.4
The issue is that it doesn't create the window each time. Release on close is a bit of an annoying option and generally is only used if you know the window controller is also being released when the window closes. (Note I've never used MacRuby so I'll be giving code in Obj-C as I know that it is correct, hopefully you can convert it. I'll be assuming GC is on as it should be with MacRuby).
Now there are two ways to do this. I'm not entirely sure how your NIB/classes are set up as it could be one of two ways.
--
The first way to solve it is to use the outlets you use to reference the form elements to blank them out when you display the window again eg [myTextField setStringValue:#""]. If you're using cocoa bindings then it's a little trickier, but basically you have to make sure the bound object is blanked out. I would recommend against bindings though if you are new to Cocoa.
--
The second way is to make the AddNewAccountController class a subclass of NSWindowController. When you press the + button you would then create a new instance of it and display it (remember to store it in an ivar). The best way to do it would be as so:
if (!addAccountController) {
addAccountController = [[AddNewAccountController alloc] initWithWindowNibName:#"AddNewAccountController"];
[[addAccountController window] setDelegate:self];
}
[addAccountController showWindow:self];
This prevents a new instance being made if the window is already visible. You then need to implement the delegate:
- (void)windowWillClose:(NSNotification *)notification {
//If you don't create the account in the AddNewAccountController then do it here
addAccountController = nil;
}
Obviously you would need to move the window to a separate NIB called "AddNewAccountController". In this NIB make sure to set the class of the File's Owner to AddNewAccountController and then to connect the File's Owner's window outlet to the window.
When all this is set up, you will get a fresh controller/window each time. It also has the benefit of splitting up nibs and controllers into more focused units.
--
One last thing. While it is fine to do something like this in a window, you may want to eventually look at doing this via a sheet, as it would then prevent the possibility of the add account window getting hidden behind other windows.

Resources