Unknown class QuoteDetailViewController in Interface Builder file with Xcode 12 - swift

I saw a lot of posts about this error in Xcode but all of them are quite old. I'm learning how to code in Swift and I'm following the instruction of book.
My Xcode is version 12.5.1. The goal of this app is to display a list of quotes (string) and when I tap on one of them, display a new view that has as a title the quote.
I have a very simple storyboard. There is a TableView with a segue to a View. I created a new Cocoa file for tableview. TableView is working.
I connect the TableView with the View.
I repeated the some process for the View. I added a new Cocoa file called QuoteDetailViewController, click on top of the view and in the Class I selected from the list the file.
When I run the application in the iPhone 11 simulator, the view doesn't have any quote as title. I put a breakpoint in the code connected to the TableView and the app stops there. If I put a breakpoint in the QuoteDetailViewController nothing happens but I see an error in the output
2021-08-11 19:13:17.215204+0100 QuoteApp[80238:4055489] [Storyboard] Unknown class QuoteDetailViewController in Interface Builder file.
The QuoteDetailViewController is very basic.
import UIKit
class QuoteDetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let quoteViewController = segue.destination as? QuoteDetailViewController {
if let selectedQuote = sender as? String {
quoteViewController.title = selectedQuote
}
}
}
}
I tried to build again and again the app. I tried to Clean Build Folder and build again. I tried to recreate the View and the code. After all of that, nothing changed. The error is still there.
The source code is on GitHub.
Update
If I click on the arrow at the end of Class and just before the dropdown, Xcode opens the file I expect to be opened.

Select the QuoteDetailViewController, open Side Inspector view and Update the Target Membership same as QuoteTableViewController
Select the controller On the Storyboard, and Add it to the module.
Check Screenshots for reference:

So, I said that in the QuoteDetailViewController I have this code.
import UIKit
class QuoteDetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let quoteViewController = segue.destination as? QuoteDetailViewController {
if let selectedQuote = sender as? String {
quoteViewController.title = selectedQuote
}
}
}
}
The error was that the function prepare must be in the QuoteTableViewController.

Related

windowWillClose and button action not called Swift

I'm designing a mac app with Xcode 10 (beta) and I got an issue with the Preference Window Controller
I have in my Main.storyboard a NSWindowController of custom class PreferenceWindowController with a toolbar. Here are its connections :
Here is the full class :
class PreferenceWindowController: NSWindowController, NSWindowDelegate {
#IBAction func didClickAuthor(_ sender: Any) {
print("author")
}
#IBAction func didClickTypo(_ sender: Any) {
print("typo")
}
override func windowDidLoad() {
super.windowDidLoad()
}
func windowWillClose(_ notification: Notification) {
print("willClose")
}
}
The window is initiated via the AppDelegate class with this code :
let storyboard = NSStoryboard(name: "Main",bundle: nil)
if let wc = storyboard.instantiateController(withIdentifier: "PreferenceWindowController") as? PreferenceWindowController
{
wc.showWindow(self)
}
The window opens as expected, with the toolbar clickable, but no functions from PreferenceWindowController are called at all, neither the closing of the window, nor the clicks on the toolbar.
I checked every connections, every class name, and I really don't know what's wrong...
SOLUTION
The solution is to store the PreferenceViewController class inside the AppDelegate class as a variable.
My solution :
var preferenceWindowController:PreferenceWindowController? = nil
#IBAction func clickPreferences(_ sender: Any) {
if let wc = storyboard.instantiateController(withIdentifier: "PreferencesWindowController") as? PreferenceWindowController {
let window = wc.window
preferenceWindowController = wc
wc.showWindow(self)
}
}
Thank you for helping !
The comment above seems like it could be on the right track. Based on the code context you've included in your question, it looks like the window controller you create will only have a lifetime for that function call.
Try making the window controller an instance variable. This is normally how I wire things up in an App delegate that creates window controllers. It's a simple pattern that works well.

Segue w/ Tab View Controller Keeps Passing Value

I am working on an iOS application that is built around a Tab View Controller. I have created a "Contacts" tab, where a user can find and select a contact from a list. When the user selects the contact, it takes the contact's name and passes it to a different tab. That function is being done like so:
func passName(name: String) {
let navTab = self.tabBarController!.viewControllers![2] as! UINavigationController
let homeTab = navTab.viewControllers[0] as! MainController
homeTab.passedName = name
tabBarController?.selectedIndex = 2
}
Everything works as it should so far (name is loaded into text field). My issue is that the value seems to keep coming back every time I change tabs and then go back to my Home tab. For example, if I select "John" from my contacts, it will take me to the Home Tab and put John's name in a textfield. Let's say I delete the last two letters of the name, so now it is "Jo". If I load a different tab and come back, the name field has been reset to "John". It's as if the value gets re-passed every time I open the Home Tab. Also, every time I load the Home Tab after passing a name, my console prints: "Name Passed: John", so it shows that this is being processed every single time the tab appears. Here is my code for processing the name:
var passedName: String!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Checks if name was passed to controller
if let validName = passedName {
print("Name passed: \(validName)")
nameTextField.text = validName
}
}
Am I passing the data incorrectly? I was thinking it might be because I have the above code being called in the viewWillAppear method, but that doesn't make sense, as essentially the data is only being passed one time from the Contacts tab. Thanks!
The problem is that you're not actually passing the value back to the original view. Apple's recommendation for passing information between classes is to use the delegate pattern. This allows the modal view to call the delegate class's function, which changes the name local to the original view because that function is declared in the original view's viewController. You can read more about the pattern in this tutorial, but I've also included a brief example relevant to your use case below.
mainViewController:
class namesTableViewController: UITableViewController, editNameDetailsViewControllerDelegate {
var name : String
#IBAction func editButtonPressed(_ sender: UIBarButtonItem) {
performSegue(withIdentifier: "editPerson", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "editPerson" { //Modal segue
let navController = segue.destination as! UINavigationController
let controller = navController.topViewController as! editNameViewController
controller.delegate = self
if let person = sender as? Person {
print("Sending person to edit")
controller.personToEdit = person
}
} else {
super.prepare(for: segue, sender: sender)
}
}
//Protocol function
func changeName(n: String, controller: UIViewController) {
name = n
dismiss(animated: true, completion: nil)
}
}
editNameViewController:
class editNameViewController: UIViewController {
#IBOutlet weak var personNameTextField: UITextField!
var personToEdit : Person?
weak var delegate : PersonTableViewController?
override func viewDidLoad() {
super.viewDidLoad()
if personToEdit != nil {
personNameTextField.text = personToEdit?.name
}
}
// Button Actions
#IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
delegate?.personDetailsView(n: personNameTextField.text, controller: self)
}
}
Finally, the protocol class :
protocol editNameDetailsViewControllerDelegate : class {
func personDetailsView(n: String, controller: UIViewController)
}
Hope this helps.
The problem is "passedName" variable doesn't changed its value every time you edit it in your UITextField. Keep in mind that every time you change tabs, the UIViewController will call viewWillAppear and viewDidAppear. So your UITextField will always show passedName value once you select other tab and return.
I suggest that every time you edit the textfield you should update passedName value.
Sorry for my bad english.

Is it possible to have 2 times prepare for segue for 2 different view controllers?

I am swift beginner and I am struggling with my first application. Sorry if my question is too basic, but I get an error message in my code here:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let secVC: NavigationViewController = segue.destinationViewController as! NavigationViewController // here is the error
secVC.receiveImeNaSladkarnica = Label1.text!
secVC.KordaA = Shirina.text!
secVC.KordaB = Duljina.text!
secVC.PodImeNaObekt = Label2.text!
I have created 2 different buttons: Navi Me and More Info buttons.
The first one (Navi Me) is connected with another view controller which is called NavigationViewContorller, there I send all of the data I need by using prepare for segue. Everything was working perfect, but now I have created another button which is called (MoreInfo).It is connected with 3rd viewcontroller called MoreInfoViewController. I think I have connected everything fine, but still when I click on the MoreInfo button the app stops working and I get the following error: Thread 1: signal SIGBART in the marked line. I cannot understand why is it breaking when this segue is for another view controller, nt for the MoreInfoViewController. Would you please advice me what to do or provide me with an example how to fix it
I have tried that:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
switch segue.identifier {
//error here-> case "VC1" :
let secVC: NavigationViewController = segue.destinationViewController as! NavigationViewController
secVC.receiveImeNaSladkarnica = Label1.text!
secVC.KordaA = Shirina.text!
secVC.KordaB = Duljina.text!
secVC.PodImeNaObekt = Label2.text!
//error here -> case "VC2" :
let secVC2: MoreInfoViewController = segue.destinationViewController as! MoreInfoViewController
secVC2.receiveImeNaSladkarnica = Label1.text!
secVC2.KordaA = Shirina.text!
secVC2.KordaB = Duljina.text!
secVC2.PodImeNaObekt = Label2.text!
default:
break
It still doesn't work
Each segue is supposed to have an unique string identifier.
For multiple view controllers use a switch statement
switch segue.identifier {
case "vc1" :
// prepare to go to vc1
case "vc2" :
// prepare to go to vc2
default : break
}
Once again my yesterday comment:
Since you are a beginner in Swift please learn first to consider the naming convention that variable names start with a lowercase letter.

Data between view controllers not passing

I am creating an application in which there are 6 view controller in storyboard. The thing is that data is shared between the default view controller and the first one ( say A and B) which i added. i am using the prepareforseque method for passing data. the problem started when i added two more view controller. lets say C and D i created two new swift files and changed the two view controller class name. i created a textbox and button in C and label in D. when i pressed the button, the value of the text field is not passing into the D view controller although i used the same methods and code which i used for A and B. do i have to do anything else when i want to pass data between two newly added view controller.
first viewcontroller in which when a button is pressed value 1 needed to be passed:
class PlaySelectMenu: UIViewController {
var value = Int()
#IBAction func twotofive(sender: AnyObject) {
value = 1
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextView : PlayGameView = segue.destinationViewController as! PlayGameView
nextView.x = value
}
}
the second view controller which receive the value and print it
import Foundation
import UIKit
class PlayGameView: UIViewController{
var x = Int()
override func viewDidLoad() {
super.viewDidLoad()
print(x)
}
}
here i have added both the view controller from the object library and not working with the default one which is present in storyboard by default. i dont know why these two viewcontroller are not working. please help.
Regards Dev
One solution would be to write the data out to NSUserDefaults and then read it back from NSUserDefaults in the other view controller. Probably not the proper or correct way to share data between two view controllers, but it's been a reliable work around for me.
Other than that, you'd need to share your code so that we can see what's occurring.
Can you post also the code in your controllers C & D. And also if you have copy/paste the code inside your first two controllers into the two others, are you sure that in your prepareForSegue method you have changed the name of the destination segue ?
Assuming you have created the segue in Storyboard:
All you need is to do is put all of needed updates in prepareForSegue because twotofive is called after prepareForSegue.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
value = 1
let nextView : PlayGameView = segue.destinationViewController as! PlayGameView
nextView.x = value
}
Since you have connected your segue from button click to view controller, when you press button segue is automatically called. Instead of connecting segue from button to VC, connect VC to VC. Then in button click method at the last add below line:
#IBAction func twotofive(sender: AnyObject) {
value = 1
self.performSegueWithIdentifier("<Name of the segue identifier>", sender: self)
}
This will call your prepareForSegue. If you are calling more then one VC using segue from a VC then you can use segue.identifier to check which VC was called as below
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "CVC" {
}

No Segue with Identifier Error in Swift?

I am trying to use the performSegueWithIndentifier function to to create a segue from one ViewController to the next. But, when I press the button with the UITApGestureRecognizer connected to it, the View shifts to the debugger panel.
Here is the error it is displaying:
ContaminateTargetViewController: has no segue with identifier 'showMasterChemistryViewController'
(I cut out the personal Info)
Here is the ViewControllers Class:
import Foundation
import UIKit
class ContaminateTargetViewController: UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showMasterChemistryViewController" {
let chemistryMasterViewController = segue.destinationViewController as! ChemistryMasterViewController
}
}
#IBAction func showPlaylistDetail(sender: AnyObject) {
performSegueWithIdentifier("showMasterChemistryViewController", sender: sender)
}
}
I also previously had to manual segues from the 2 buttons I have on the ViewController and recently deleted them to switch over to the UITapGestureRecognizer for the convenience. I am wondering if I have an error in my code that I do not see or if previously deleting the manual segues from the View is causing this error. If the problem is rooting from the previously deleted manual segues please tell me how to fix this in your error. If the problem is rooting form the code, please leave the code I should add, delete, or substitute.
Any suggestions or input is greatly appreciated.
Thanks in advance.
This error is called when you do not have the requested segue connected to your view controller. Are you sure that you have the two view controllers connected via a segue named "showMasterChemistryViewController" on your storyboard?