how to apply condition based custom segue in storyboard - xcode

i am working on storyboards which has couple of views on first view a condition is placed i want if the condition satisfies then only navigation should happen
For this i have used Custom segue but no matter my condition satisfies or not it navigates to new view.
I have created method in custom segue class
- (void) perform{
NSLog(#"source %#",self.sourceViewController);
NSLog(#"dest %#",self.destinationViewController);
UIViewController *sVC=self.sourceViewController;
UIViewController *dVC=self.destinationViewController;
[sVC.navigationController pushViewController:dVC animated:YES];
}
I want to set condition if result is 1 then only it should navigate. Woul prepareforsegue or initwithsegue provide me any help

Are you saying that you only want to perform the segue if a condition is true?
If so, instead of creating the segue directly from a control or table cell, create a triggerless segue. A triggerless segue has the view controller as its source, and it won't ever fire automatically. Instead you can fire it programmatically any time you like, including from an IBAction.
To create a triggerless segue, start control+dragging the segue from the containing view controller icon in the scene dock at the bottom of the scene. Drag to the destination scene like normal, and pick the segue type. Select the segue, and in the inspector, choose a segue identifier.
At runtime, when you want to perform the segue, invoke -[UIViewController performSegueWithIdentifier:sender:]. You can pass any object you'd like for the sender, including nil. If the sender has no use to you, pass nil.
So, in summary:
Create a triggerless segue from the view controller to the destination scene
Set an identifier for the segue in the inspector
At runtime, and form code, call -[UIViewController performSegueWithIdentifier:sender:] when you want to trigger the segue.

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?

Draw manual segue to myself

I have a view controller contains a table view that displays list of items. Each item could contains list of items (or could be a leaf).
To drilldow the list items, I would like to create a show/push segue, kinda in recursively way, but I seem not able to draw the manual segue to the view controller itself?
Is it supported?
I was playing around with it just after leaving that first comment - I don't think you can have a manual segue to the same view controller!
The best thing to do would be to give that view controller a storyboard identifier (e.g Selection and then create an instance of that view controller with (in Swift):
let subCategoryVC = storyboard.instantiateViewControllerWithIdentifier("Selection") as! SelectionViewController
or in Objective-C:
SelectionViewController *subCategoryVC = (SelectionViewController *) [self.storyboard instantiateViewControllerWithIdentifier:#"Selection"];
(Docs for UIStoryboard.instantiateViewControllerWithIdentifier:)
You could put that in your table view section method along with a manual segue to the leaf view controller.
(The code above assumes the view controller with the table view is called SelectionViewController!)
As Rich mentioned, this is probably not doable as for today. There are two workaround/solutions I can think of:
Instaniate the vc programatically from storyboard and programatically
use navigationController to push it. (I think this is what Rich was
talking about.)
Embed the View Controller in another Navigation Controller and draw
the manual segue to the Navigation Controller.
I choose the 2nd one just because it is very easy and more visual in storyboard. The first one should just work, too.

Tabbed view with 3rd view?

I have a tabbed app with two tabs and associated views (two views). One view is a tableview. When a cell is clicked, I'd like to display another view, which will be related to the cell contents.
This introduces a 3rd view that isn't accessed via the tabs. How do I bring in the 3rd view?
I'm guessing drop another viewcontroller onto the story board? But from there, how do I push the 3rd view into visibility upon tableview cell click?
Instead of having one UITabBarController connected to two UIViewControllers, connect your UITabBarController to a UINavigationController and a UIViewController. Put your UITableView inside the UINavigationController as root view controller. When a user taps on a cell, just perform a segue to yet another UIViewController that you push onto the navigation controller's stack.
Something like this:

Why can't I connect my menu to my view controller IBAction?

I have a document based application. I have just created menu items in the storyboard and IBActions in my view controller. However the usual way I connect an action to a target doesn't work
-(IBAction) markAsHidden:(id)sender;
-(IBAction) markAsVisible:(id)sender;
-(IBAction) toggleHidden:(id)sender;
Here is what I see when from my menu item I press Ctrl and mouse click from menu to View Controller. It does not show my IBActions.
Any idea ? My 2 cents guess is that it has to do with the app being document based but... not really sure
Connect the menu items to the application scene's First Responder. When you connect to the application scene's First Responder, your view controller's IBActions should appear in the HUD's list of available actions instead of the action segues shown in your screenshot's HUD.
Why can't I connect my menu to my view controller IBAction?
Because your menu items and view controller are in different scenes in the storyboard. You can think of a scene as an independent graph of objects that are instantiated when the scene is loaded from the storyboard. Objects in different scenes can't be connected together in the storyboard because they're not loaded at the same time.
Just for fun, try creating an instance of your view controller in the Application Scene in your storyboard. To do that, you'll probably need to drag a plain old NSObject instance into the scene and then set its type. Once you do that, you'll find that you can drag a connection from a menu item to that view controller just as you'd expect, but you can't drag a connection to a different object of the very same type in a different scene.
Note: Once you've played around enough to convince yourself that it works, remember to delete the view controller that you added. A view controller without a view is like a duck without a quack, and a view controller and its view hierarchy should be in their own scene.
My 2 cents guess is that it has to do with the app being document based
No, it doesn't have anything to do with that. You'd have the same problem in an app that's not document-based. You'd also have the same problem if your app were .xib-based instead of using storyboards, since the controller you'd be trying to connect to would be in a completely different .xib file.
The easy solution, as Mark already described, is to use the responder chain. The First Responder proxy object is part of every scene, so you can always make connections to it. When you connect a menu item to First Responder its target will be nil, which tells NSMenu to walk the responder chain until it finds an object that responds to the menu item's action message. It then sends the message to that object.
If you are converting a project from objective C to Swift, do not make my mistake. When writing your IBAction write like this:
#IBAction func someAction(_ sender:AnyObject) {
// this will work
}
Do not omit the underscore before sender or the Interface Builder won't be able to connect to your action as in here:
#IBAction func someAction(sender:AnyObject) {
// this won't work and IB won't connect to this action
// because sender will be part of the symbol name
}

XCode Storyboard: how to create a segue when the segue trigger is not on storyboard

So I started playing with storyboards in XCode 4.3.2. I started with the Master-Detail application (split view application for iPad). In the detail view (named DetailVC) I have a view where I displayed an array of custom views.
The custom views (named GridView) have a tap gesture recognizer which is supposed to handle the tap event on each custom view. Tapping a GridView pushes a view controller show some search results (named SearchResultsVC).
With GridView created in a separate nib file, and the DetailVC and SearchResultsVC reside in storyboard, how can I create a push segue with destination SearchResultsVC? I just created a segue between DetailVC and SearchResultsVC? Is there someway I can trigger this segue programatically from inside the GridView class when tap gesture is recognized????
In the method where you handle the tap use:
[self performSegueWithIdentifier:#"yourSegueIdentifier" sender:self];
In your StoryBoard control drag from your DetailVC to your SearchResultVC and choose what type of segue you would like. Make sure to name your segue identifier the same as the one in the method above in attributes inspector.
I'm gonna try and improve my answer I messed it up I think:
1) In your DetailVC.h create an instance variable for your GridView like this
IBOutlet UIView * gridView;
also create a getter method and an IBAction for your grid view like this
-(UIView *)gridView;
-(IBAction)myGridGotPressed:(id)sender;
2)Now in your DetailVC.m implement your methods like this
-(UIView *)gridView{
if(!gridView){
[[NSBundle mainBundle] loadNibNamed:#"GridView" owner:self options:nil];
}
return gridView;
}
Also implement your IBAction like this
-(IBAction)myGridGotPressed:(id)sender{
[self performSegueWithIdentifier:#"yourSegueIdentifier" sender:self];
}
3) To make this work you need to change the filesOwner class of your GridView to DetailVC and then hook up the outlets and Actions as normal.
I hope that helps.

Resources