I create rounded user icons with a custom UIImageView class. I make these image views interaction enabled, so that when a user taps on one of them, it should segue to another view controller.
I can successfully get each users data printed upon tapping an icon, but I keep getting error "no segue with identifier 'confirm'", even tho I have triple checked that that is the correct identifier. Can one not segue this way?
Here is the code to run when an icon is tapped (this is located inside the icon.swift file) I create an instance of the controller to access the segue on tap:
#objc func iconWasTapped() {
//
var controller = ConfirmOpponentController()
print("\(game.playerOne?.username ?? "") VS \(game.playerTwo?.username ?? "")")
controller.segue()
}
Here is the segue method inside the view controller file:
let SEGUE_TO_CONFIRM = "confirm"
func segue() {
self.performSegue(withIdentifier: SEGUE_TO_CONFIRM, sender: nil)
}
Inside the storyboard, I have controlled dragged and created a push segue, and named it 'confirm'. I did NOT control drag from a button, or an icon. I just linked up the view controllers.
I think in easy way you can Add a tap gesture recognizer to the image view, set the action to be a segue going to your destination view controller, add an if statement to your "prepareForSegue" function.
Related
I'm developing a SpriteKit game with two different scenes (MainMenu.sks and Settings.sks). I also have a UIViewController.
From the MainMenu the user can tap "Settings" which causes the app to load the Settings.sks scene and present it.
It's done using this code:
// Move to Settings.sks
let transition = SKTransition.flipVertical(withDuration: 1.0)
let loadScene = SettingsScene(fileNamed: "SettingsScene")
loadScene?.scaleMode = self.scaleMode
self.view?.presentScene(loadScene!, transition: transition)
From the Settings.sks scene the user can tap on the SKLabelNode "Change username" which causes the app to load the UIViewController by performing a segue.
The UIViewController contains a UITextField and a UIButton. The UIButton takes the user back to MainMenu.sks.
However, when I'm doing so the it's like a new scene of MainMenu is placed upon the other causing the app to sort of "freeze" and not responding to any touch gestures. I can see from the nodeCount that the nodes are doubled.
A workaround is loading the UIViewController directly from the MainMenu.sks (also via a segue). By doing so, the app works just fine.
I'm suspecting the problem to be the way I load Settings.sks.
What am I missing? Maybe unloading the entire SKView before exiting?
Performing a segue will present a new view on top of the stack. By using a segue to return to the main menu, the app will create a new main menu on top of the UIViewController. I can't say for certain why your app freezes. But I would guess that there are some properties or functions that don't work properly when a new main menu is created and presented from your UIViewController.
I recommend unwinding the segue used to reach the UIViewController instead. This way you can return to the previous view and conserve memory.
You'll need to write an IBAction in your destination view, the main menu in this case:
#IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
}
Then ctrl-drag from your button in the UIViewController to the exit icon in storyboard. You should see an option to use the IBAction unwindToMainMenu that you just wrote. This will create an unwind segue.
A complete guide to unwind segues and multiple examples can be found in this answer: What are Unwind segues for and how do you use them?
I have a toolbar on my macOS app, developed in Swift. The toolbarItem is dragable onto the NSWindowController, and I can setup an IABAction function, I just have a print in the function at the moment. And when I click on the button nothing happen the click does not seem to be recognised as an action ?
I had a few more line of code in the function but deleted it and now have just the print("test") line.
#IBAction func exportCsvClicked(_ sender: NSToolbarItem) {
print("test") }
No output observed, so I'd love to get "test" in the console when I click on this button.
Here is a list of the connections associated with the toolbarItem.
I found a way to get around the fact that the IBAction from an NSToolbarItem does not recognise the click on this item:
1/I made a customSegue from the item to the main window controller (it can go anywhere)
2/The prepare for segue function posts a notification to the notification saying that the item has been clicked.
3/The main view controller observes the notification and presents, either has a popup or a sheet (I got two buttons), the view that I have setup in the storyboard (referencing with the storyboardID). I found that you need to pass on all the necessary variable to setup the view from the main view Controller, and that there was issue of code in the viewDidLoad function of the sheet/popup view not running, I am suspecting that they might be different instances.
In my macOS application I have menu items, which are replicated also in main UI. Application is consisted of main window with its delegate and single view along with its view controller. In app delegate I capture menu item click action, then I need to send this event to my view controller in order to take appropriate actions and also update main UI.
Question is how to access my view controller (NSViewController) from app delegate?
If you have window as an IBOutlet you can do
var rootViewController: MyViewController? {
return window!.contentViewController as? MyViewController
}
func sendPressed(_ sender: Any?) {
rootViewController?.sendPressed()
}
If you don‘t have a window variable you can get it through
NSApplication.shared.orderedWindows.first!
Actually you don't need a reference to the controller. There is First Responder
Declare the IBActions
In Interface Builder connect the menu items to the First Responder (red cube) of the target object and choose the appropriate action.
The action will be executed in the first object of the responder chain which implements the action.
I need to Open a URL when the user clicks on a Menu Item.
Currently I'm using the following code
url = URL(string: "https://www.example.com/test")
NSWorkspace.shared().open(url)
This works fine from a Button.But I cannot connect a Segue from the Menu Item to the view controller inorder to setup an IOAction,so that I can write the necessary code.
How can I solve this problem? Please advice.
Segues are for opening new views or windows from your app. You should implement your function as ordinary #IBAction in your view controller or app delegate, and connect action under Sent Actions in the Connections Inspector with the First Responder in the storyboard scene. You will find your action method there. Cocoa touch will automatically enable or disable the menu item weather the view controller is in the responder chain. If you implement the action method in the app delegate the menu item should always be enabled, because the delegate is always in the responder chain.
#IBAction func openURL(_ sender: AnyObject) {
let url = URL(string: "https://www.example.com/test")
NSWorkspace.shared().open(url)
}
Implement the method as IBAction in the view controller.
Connect the NSMenuItem to First Responder (red cube) of the Application Scene and select the method.
If there are multiple implementations of the method the framework executes the first in the responder chain.
I have the following setup:
I have a UIViewController embedded in a UINavigationController. I have a second UIViewController embedded in a second UINavigationController. I need to call the second UIViewController in two ways. I have two buttons set up on the first UIViewController. The first button has a segue created by control-click-drag between the button and the second UINavigationController. When I click the button, the second view controller displays. The second button calls the created segue using performSegueWithIdentifier like this:
#IBAction func segueTwoButton(sender: AnyObject) {
performSegueWithIdentifier("ShowSecondView", sender: self)
}
In both cases the second view controller displays correctly.
But, I have some information that I want to pass. So in the prepareForSegue function, I have this:
let vc = segue.destinationViewController as! SecondViewController
This fails, because the segue is going through the second UINavigationController to get to the second UIViewController.
I've come up with two ways of handling this.
I can use the following in the prepareForSegue
let vc = segue.destinationViewController.childViewControllers[0] as! SecondViewController
I can add a UINavigationController class and then pipe it through there, but that seems like a lot of work to do this.
Both of these ways work, but is this the best way, or is there some other way that I should consider handling it?
Second question - Assuming that I do it this way and put a UINavigationController class in so that I can pass the information along, what is the proper way to unwind? I can create an unwind segue that will go straight from the second view controller, back to the first, but is it acceptable to do it this way? Or would I need to unwind to the UINavigationController class and then to the first view controller?
I'm not sure why you decided to embed another navigation controller within another. Generally, if you embed a navigation controller one time that will suffice for the rest after you've set up your other segues. So first thing's first delete that second nav controller.
Secondly, from experience, I would always avoid control dragging from anything other the view controller itself. Otherwise, you get duplicate calls to perform segues. So go ahead and delete all remnants of the prior segues you created with the buttons. Instead, Control drag from the top yellow view controller icon to the next view controller. make sure you name the segue arrow so that you can properly performsegueWithIdentifier
Now you should have First View directly segued to the Second View. This will be easier to pipe or funnel information through the segue function exactly like you had coded above
let vc = segue.destinationViewController as! SecondViewController
Global Variable ( will replace segue funneling information )
Lets take this as an example. Say I wanted to recored the user's name on the first view controller.
// First View Controller
private let userName: String
// After that we can create a new object called NameSingleton
class NameSingleton {
// NameSingleton.swift
var UserName:String = " " // Since its global this value will change
static let sharedinstance = NameSingleton()
}
// Now hop back over to your first ViewController
// before you trigger your segue assign whatever data you need to your
// singleton. In this case, a name.
// First View Controller.swift
#IBAction func segueTwoButton(sender: AnyObject) {
NameSingleton.sharedInstance.UserName = "Hi"
performSegueWithIdentifier("ShowSecondView", sender: self)
}
// Now if you go to the second view controller and access it, the name
// will be stored in the singleton. (Great for moving huge pieces info
// (i.e. structs, objects, lists)