Does anyone know what the new Exit icon is used for when editing storyboards using Xcode 4.5? - interface-builder

Right-clicking the Exit icon yields an empty window. Can't Ctrl-drag a connection to any IB elements or corresponding source files. Docs give no love. Doesn't appear in nib files, only storyboards. My assumption is that it's a corollary to segues, but I don't see any new methods to back it up. Anyone?

I had a hard time following the accepted answer so here is more detail.
Given the photo below on view controller C you can "exit" back to any view controller in the segue path.
ViewController A you can write:
- (IBAction)done:(UIStoryboardSegue *)segue {
// Optional place to read data from closing controller
}
ViewController B you can write:
- (IBAction)back:(UIStoryboardSegue *)segue {
// Optional place to read data from closing controller
}
ViewController C you control drag from "back" button to the green exit option and select back:
ViewController C you control drag from "done" button to the green exit option and select done:
Note: Even though the methods are on other view controllers they show up for the ViewController C's exit. Control dragging and selecting a method defines which ViewController to unwind to.

There's a lot of information in the WWDC video "Session 407 - Adopting Storyboards in your App."
Say you have two view controllers linked by a segue. Implement the following exit action on the first view controller:
- (IBAction)done:(UIStoryboardSegue *)segue {
NSLog(#"Popping back to this view controller!");
// reset UI elements etc here
}
Then, on Storyboard scene for the second view controller, Ctrl-drag from a UI element, such as a button, to the exit icon at the bottom of this view controller. The done: action you added to the code of the first controller will appear as an option. Now, activating the button you Ctrl-dragged to the exit icon will pop back to the first view controller and maintain its original state (ie UI elements such as text input supposedly still intact).

As addition to Eric answer here is how it works with swift:
The function you add to the destination controller looks like:
#IBAction func backFromOtherController(segue: UIStoryboardSegue) {
NSLog("I'm back from other controller!")
}

Related

How do I set the initial first responder per view in a cocoa app that switches between different views?

My Cocoa App uses one ViewController. I do not use the InterfaceBuilder On app launch a view will be created and the user can do stuff. When clicking a specific button the VC (as the view's delegate) receives a message and then replaces the view with another.
In this new view I want a specific UI element to be the first responder. So far I have not been successful.
The new view has a reference to the desired element (a subview), so the VC can pass it to the window's makeFirstResponder(:_) method.
I tried to do that in the following places:
at the end of the view's init
in the view controller's viewWillAppear()
in the VCs viewDidAppear()
in the latter two I tried:
if let myView = self.view as? MyView {
... here I try to set the UI element as firstResponder ...
}
But in any case I get the following Message:
[General] ERROR: Setting <NSTableView: 0x7f8c1f840600> as the first responder for window <NSWindow: 0x7f8c1ef0efc0>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
So it appears that at the time I try to set the firstResponder the new view has not yet been attached to the window.
What I also tried is to override the MyView's becomeFirstResponder()method, assuming that when the view is finally presented in the window it will receive that command, but unfortunately this method does not get called.
Is there an easy way to specify an entry point for the responder chain / key view loop per view?

Need help to write different if statement

(I am) new in the Xcode.
I am making this app, and first I had 3 viewcontrollers; each used to talk with each other with a button: from the first you click a button that goes to the second, and go on. The thing is: I put some switchs in the first viewcontroller and they execute a segue for the second viewcontroller, changing a label. The first viewcontroller has 2 buttons - one of them is part of the segue of the switchs, and the other is for the third viewcontroller. Now my problem: when I click the second button on the first viewcontroller it works just fine, but if click the swicth but not the button of the segue, instead the second button the app crashes.
this is the line of my segue:
if switch1?.isOn == true
{
let secondController = segue.destination as! SecondViewController
secondController.myString1 = "blabla"; ()
As I said: it doesn't interfere in the normal use of the app, but if I click the switch, but not click the button for the segue, instead click the button for the third viewcontroller, the app crashes.
Could not cast value of type 'app2.ViewController' (0x103879548) to 'app2.SecondViewController' (0x1038793a0).
2020-02-25 20:43:39.507421+0000 app2[18433:249963] Could not cast value of type 'app2.ViewController' (0x103879548) to 'app2.SecondViewController' (0x1038793a0).
I need a way to write a condition that if other button is click other than the one of the segue, the switchs should be off.
Any help would be highly appreciated.
This error message you're getting means that segue.destination is not of type SecondViewController and in fact it appears to be of type ViewController. More than likely what this means is you have to go into your Storyboard and more closely examine:
Your segue to see if its destination is in fact of type SecondViewController
The Custom Class part of the storyboard Identity Inspector to make sure you picked a Class and Module for the view controller in question
The above answer is all pretty much in this post, plus some more context/details

Perform segue after unwinding

I have a main screen wrapped in a navigation controller.
The main screen has several buttons that trigger segues to other views. One button goes to a table view.
A selection in this table should trigger a segue that is normally performed by one of the buttons on the main view.
I was assuming that I need to unwind to the main screen first, and then trigger a segue from the unwind segue programmatically, but what happens when I do that is that it performs the programmatic segue first, then unwinds, and ends up on the main screen again.
What is the correct way to deal with this situation? I don't want to be able to go back to the table view after the programmatically called segue, the back button should then go to the main view.
In case it helps to explain my use case a little more: The table view is a list of levels. A selection should launch my game view with the level picked in the table view.
My unwind segue in my main view:
#IBAction func backFromLevelSelectionUnwindSegue(segue:UIStoryboardSegue) {
performSegueWithIdentifier("playSegue", sender: self)
}
obviously playSegue is the segue to the game view controller.
An answer to a similar question suggests setting a boolean flag and then performing the segue in viewDidAppear, but it seems like that viewDidAppear should not have to know about an unwind segue that has occurred. Is there a "correct" solution that I haven't come across?
In your backFromLevelSelectionUnwindSegue, your are still in a unwind segue context. So call performSegueWithIdentifier after the context finished using dispatch_async or performSelector:withObject:afterDelay like below.
#IBAction func
backFromLevelSelectionUnwindSegue( segue:UIStoryboardSegue ) {
dispatch_async( dispatch_get_main_queue() ) {
self.performSegueWithIdentifier( "playSegue", sender: self )
}
}
Would it be possible for you to perform a segue to the game view without unwinding it to the main screen? Then when you unwind the segue, unwind it to the main view instead of back to table view? If I remember correctly, we are able to unwind past the presenting view controller.
This is a matter of opinion, but in your case I think you should simply have a segue between the tableview and the game, with any extra data necessary being passed to the tableview VC from the main VC.
If you need go back multiple viewControllers in a UINavigationVC, I would look at using popToRootViewController or use an unWind between them. e.g. call unwind from the 3rd viewController, with the handler in the 1st viewController
It's possible to have multiple unwind segues that go back to different places. In the scenario given the view controllers should be arranged Main->LevelSelect->Game
and then when game ends you have buttons for 2 or 3 unwind segues. First one is exitToGameStart that allows the player to restart the same level. exitToLevelSelect allows player to choose a new level. And optionally exitToMainMenu goes all the way back to the start. For a full example, see Apple's UnwindSegue sample, and in particular the "Start Over" button on the last table that performs the exitToQuizStart unwind segue and the "Return To The Menu Screen" that performs the exitToHomeScreen unwind segue. Code for the receiving methods are below:
QuestionViewController.m
//! Unwinds from the ResultsViewController back to the first
//! QuestionViewController when the user taps the 'Start Over' button.
//
// This is an unwind action. Note that the sender parameter is a
// 'UIStoryboardSegue*' instead of the usual 'id'. Like all unwind actions,
// this method is invoked early in the unwind process, before the visual
// transition. Note that the receiver of this method is the
// destinationViewController of the segue. Your view controller should use
// this callback to update its UI before it is redisplayed.
//
- (IBAction)exitToQuizStart:(UIStoryboardSegue *)sender
{
// The user has restarted the quiz.
[self.currentQuiz resetQuiz];
}
MainMenuViewController.m
//! Unwinds from the ResultsViewController back to the MainMenuViewController
//! when the user taps the 'Return to the Home Screen' button.
//
// This is an unwind action. Note that the sender parameter is a
// 'UIStoryboardSegue*' instead of the usual 'id'. Like all unwind actions,
// this method is invoked early in the unwind process, before the visual
// transition. Note that the receiver of this method is the
// destinationViewController of the segue. Your view controller should use
// this callback to retrieve information from the sourceViewController. Used
// properly, this method can replace existing delegation techniques for
// passing information from a detail view controller to a previous view
// controller in the navigation hierarchy.
//
- (IBAction)exitToHomeScreen:(UIStoryboardSegue *)unwindSegue
{
// Retrieve the score from the ResultsViewController and update the high
// score.
ResultsViewController *resultVC = (ResultsViewController*)unwindSegue.sourceViewController;
self.highScore = MAX(resultVC.currentQuiz.percentageScore, self.highScore);
}
Note: to build the old project in the latest Xcode, open the storyboard, file inspector, builds for, pick a newer iOS version.

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)

Standard Back Button in XCode (XIB)

I can't get the standard back button of iOS into a navigationBar because I can't find it in the Object Library, so can I do it with code or something else?
I just want the normal, standard, blue back button - you know which I mean.
To "automatically" have a back button you need first have a UINavigationController. Then you need to take a different UIViewController and add it as the root view controller in UINavigationController's init method:
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:someOtherViewController];
Be sure to also set a title for someOtherViewController, usually in it's viewDidLoad or initializer. I'll tell you why this is important in a second:
self.title = #"Some other VC";
Then take a second UIViewController and push it onto your navigation controller:
[navigationController pushViewController:anotherViewController animated:YES];
You now have two UIViewControllers on your navigation stack: someOtherViewController and anotherViewController.
Your view will now have a back button with "Some other VC" in it. This is the title of the view controller that was just moved out of view:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
http://simplecode.me/2011/09/04/an-introduction-to-uinavigationcontroller/
I would also suggest reading up on how UINavigationControllers work and searching this site a bit more for customizing the back button. There are plenty of threads about it.
You can't add the back button yourself. The back button is part of the Navigation controller. If you embed a Navigation controller into your view(s), the back button will appear and be populated by the name of the previous view.
If you're using storyboards select your view controller, then in top menu choose "editor" -> "embed in" -> "navigation controller".
Edit: Here is an exmaple.
I'm running Xcode 7.2. This was driving me crazy, but I figured it out. Here are all the pieces you need to make the Back button appear (make a test project to prove it):
1) You have to have a Navigation Controller and it has to be set to be the initial view controller. So add the Navigation Controller, you will import two tables. Click on the Navigation Controller and on the properties list, check the box that reads "Is Initial View Controller". You will now see and arrow pointing to this view.
2) In our case we want a ViewController and not the included / connected TableViewController, so delete the TableViewController (RootController) and add a new ViewController.
3) Connect the Navigation Controller to the new ViewController by clicking on the top bar of the Navigation controller and orange circle with the arrow pointing left. Hold the Control button on your keyboard down and click and drag from the orange circle to the ViewController and let go. When given the list of options on how to connect the two views, select 'root view controller'.
Done! Now you the functioning navigation bar and you automatically get the back arrow on all segues added. Test this. Add another ViewController and connect to it with a button on the existing ViewController. Use the Control-click-drag approach from the button to the newest ViewController. Select the 'show' option for the new segue you created.
Run it. You'll see the back option has automatically appeared when you click the button and moved to the newest ViewController.
This is all provided by the Navigation Controller, but only when you make another controller the RootController. Happy navigating!

Resources