So here is my first view controller class:
import UIKit
class AboutUsTableViewController: UITableViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let volunteerPageVC = segue.destination as! DedicatedVolunteerViewController
// Idk why I have to use 'as!' instead of 'as'. Xcode made me do it
volunteerPageVC.person = "John Smith"
}
}
Here is my second view controller class:
import IUKit
class DedicatedVolunteerViewController: UIViewController {
var person: String?
#IBOutlet weak var HeaderTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
HeaderTitle.text = "About " + person!;
}
}
On my Main Storyboard, each of the cells on the AboutUsTableView segue to the DedicatedVolunteerViewController. I want to ability to have one view controller that can be used multiple times (i.e. people's profiles).
When I click on any of the cells in the table view, I get these errors:
2016-12-26 11:44:27.075 MyApp iOS[8350:493673] Unknown class _TtC20MyApp_iOS31DedicateVolunteerViewController in Interface Builder file.
2016-12-26 11:44:29.698 MyApp iOS[8350:493673] Unknown class _TtC20MyApp_iOS31DedicateVolunteerViewController in Interface Builder file.
I'm confused since when I compile the app, it gives no error saying about "Unknown class" or an error saying I need to add/import DedicatedVolunteerViewController into AboutUsTableViewController to be able to use it. I even tried to import it, but Xcode wouldn't let me and kept giving me errors.
P.S. I've a lot of trouble considering most places online give documentation on older versions of swift or obj-c which make it hard to find out how to use new versions of code.
It sounds like the class name is wrong in your storyboard scenes. Go follow the segue(s) from your table view controller to your second view controller. Then select the scene for the destination view controller, select the view controller itself, and select the "identify inspector." Check the class of the destination view controller. From the error you're getting, it sounds like it's class is _TtC20MyApp_iOS31DedicateVolunteerViewController instead of DedicateVolunteerViewController.
Swift uses 'optionals' which essentially means a nullable object. Optionals can have a valid value or nil. It is recommended that you use the 'guard' statement to handle optionals.
So, your prepareForSegue should look like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let volunteerPageVC = segue.destination as? DedicatedVolunteerViewController else {
//Handle the nil value, log, etc
return
}
volunteerPageVC.person = "John Smith"
}
The ! is explicitly unwrapping the optional - meaning it MUST have a value or the app will crash. You should avoid using them where possible and use the ? as I show above instead with a guard statement. In the code above, it attempts to cast the segue.destination to a DedicatedVolunteerViewController but if it can't, it will fall into the guard statement (meaning the result was nil).
There's a lot of good information about optionals on Apple's site. Check out: Swift Basics
As for your specific error, it looks like a simple mis-spelling. The error is referring to 'DedicateVolunteerViewController' (missing a 'd') and your class name is 'DedicatedVolunteerViewController'
Related
I'm working on Xcode projects in Swift and I'm trying to transfer data from a "FirstViewController" to a "SecondViewController".
First of all, I receive some data by my user in the FirstViewController. I made a structure to put all these data in one single object that i try to transfer.
Here's my code :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecondViewController" {
let sentData:typeOfMyStrcuture = myObject()
let secondVC = segue.destination as! SecondViewController
secondVC.sentData = sentData
}
}
In my SecondViewController I have :
var sentData: typeOfMyStructure!
The problem is : since the type of the object i'm sending is unknown in my SecondViewController, i got the following error : "Cannot find type 'typeOfMyStructure' in scope".
I tried to write the same structure in my SecondViewController for it to recognize the type but I get this error : "Cannot assign value of type 'FirstViewController.typeOfMyStructure' to type 'SecondViewController.typeOfMyStructure'
Thanks by advance for your precious help !
Two options:
if typeOfMyStructure is created inside the first view controller declare in the second view controller
var sentData: FirstViewController.typeOfMyStructure!
Declare typeOfMyStructure outside of any view controller
Side note: Please name structs and classes with a starting capital letter
I am creating a simple quiz app in xcode that has an intro, question, and results view controller. When I try to link my "QuestionViewController" to my "ResultsViewController" with the prepare for segue method in code, the exclamation point in "as!" keyword is not highlighted in pink.. It gives me a "Thread 1: signal SIGABRT". Yes I have linked it in the storyboard previously.
I've tried checking the identifiers of the segues in the storyboard and they look fine. Here is the code I was talking about:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ResultsSegue" {
let resultsViewController = segue.destination as! ResultsViewController
resultsViewController.responses = answersChosen
}
}
It is supposed to pass the data of answersChosen to my resultsViewController, but I am getting a "Thread 1: signal SIGABRT" error. And like I said, the "!" after "as" is not highlighted in pink like "as" is. In the iBook the "!" is pink.. that indicated to me something is not connected right.
Also in the console:
Could not cast value of type 'UINavigationController'
(0x112186760) to 'CityQuiz.ResultsViewController' (0x10a61e698)
2019-07-01 14:45:35.043824-0400 CityQuiz[29761:429223] Could not
cast value of type 'UINavigationController' (0x112186760) to
'CityQuiz.ResultsViewController' (0x10a61e698)
Isn't it supposed to say cast value of type "QuestionsViewController" instead of "UINavigationController" as well? How else do I check if things are linked properly besides actually clicking on the segues in the storyboard?
Edit #1: Turns out I had an extra navigation controller, that I somehow didn’t notice. I’m new to this, thanks for the responses. I am now getting some “NSUncaughtKeyException” but I found some other posts about those errors.
why don't you present view controller programmatically ? It's much more simple than this method. I assume the problem you have in your case is that the segue "ResultsSegue" is attached to the embedded navigation controller. And you probably should not force unwrapped view controller like that. To check optional is a better way to handle presentation like below.
if let resultsViewController = segue.destination as? ResultsViewController {
resultsViewController.responses = answersChosen }
I'm trying to get an array working on xcode 9.4.1 between viewcontrollers but keep getting a sigabrt error within part of the first few lines. When playing the simulation the segues that use the array information work, but the segues that don't rely on the array information or are linked to it in any way end up resulting in a SIGABRT error within the array's code. Anyone know what's going wrong?
This is the code;
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let VC = segue.destination as! ViewController_array
if segue.identifier == "grade1"{
VC.gradeLabel = "Grade 1"
VC.display = "information goes here1"
}
if segue.identifier == "grade2"{
VC.gradeLabel = "Grade 2"
VC.display = "information goes here2"
}
}
(and the last few lines continue on as such for each grade)
The error with the code is somewhere within the first line - the receiver on the other viewcontroller is perfectly fine and no other viewcontrollers relate to the same code, it's just something within this first one here.
The sender viewcontroller is named 'ViewController' and the receiver is 'ViewController_array'
The error message it's resulting in is;
objc[11314]: Class VCWeakObjectHolder is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/Frameworks/ViceroyTrace.framework/ViceroyTrace (0x12d8504d0) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/AVConference (0x12c97ce38). One of the two will be used. Which one is undefined.
Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array' (0x10d40a710).
2018-08-18 21:06:07.764832+1000 test2[11314:111648] Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array' (0x10d40a710).
(lldb)
You need to assign class name
ViewController_array
to the VC inside IB
Have a look at the error message:
Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array'
That means that the view controller, that you are trying to segue to, is an instance of the class UIViewController and not ViewController_array. Forced casting UIViewController to ViewController_array will always fail since it is ViewController_array who is the subclass of UIViewController, not the other way around.
You have to make sure that you are setting the right view controller class in the identity inspector in the storyboard:
I am a newbie to iOS app development trying to build a tip calculator. The basic functioning of the app is completed. My Mainstoryboard has a segment control which shows three % values such as 10, 20, 30. There is a Settings button which on click takes me to a new page and shows the similar % values in a segment control.
What I want to do is that, when a number is clicked (a segment) it should be saved as the default tip% value. How should I pass this value to the Mainstoryboard function where I have written a function to calculate the tip amount?
I suppose you are using a segue for moving to the other view, so use prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "tipSegue"
{
if let destinationVC = segue.destinationViewController as? OtherViewController {
destinationVC.tipPercent = someValue
}
}
}
You can write a protocol for setting the default percentage, and have your MainViewController conform to that protocol. When a user taps a button in your SettingsViewController you can call a function (defined within the protocol) to let the "delegate" (MainViewController) know what has happened, and set your default variable accordingly. If this is a permanent setting it might be better to use UserDefaults, as this is exactly what that was designed for. Then, upon loading MainViewController you can access that UserDefaults variable, if it exists.
A little protocol help:
Your protocol could be defined very simply - something like this (and this has to be declared outside of your viewControllers - I often do it above the class declaration of a related viewController):
protocol SettingsDelegate {
func didUpdateDefaultTipPercent(to percent: Float)
}
That's it for the protocol declaration, unless you anticipate needing other functions. Note that you don't actually define the functionality of that function - each viewController that conforms to the protocol may have a different definition of that.
Then, in your settingsViewController you might have an optional variable for protocol conformer like this:
weak var settingsDelegate: SettingsDelegate?
and after the user chooses a default percentage you can safely check to see if the delegate exists and pass that new number to the delegate like so:
if let delegate = self.settingsDelegate {
delegate.didUpdateDefaultTipPercent(to: 15.0) //this "15.0" will come from your segmented control action or whatever
}
In your MainViewController, in your prepareFor(segue... you will need to check to see if you are going to settings, and set Main as the delegate:
...
if let settings = segue.destination as? SettingsViewController {
settings.settingsDelegate = self
}
And, finally, you'll need to make your MainViewController conform to the protocol. I usually do this as an extension just to make it easier to find, and to keep it separated from other things:
extension MainViewController: SettingsDelegate {
func didUpdateDefaultTipPercent(to percent: Float) {
self.defaultPercentage = percent
}
}
Using Swift 3. This question has been around and there are quite a few examples. Unfortunately none of them have worked for me. I have a uiviewcontroller that has a container view. This container view has a segue to another view controller. Everything loads up correctly and displays correctly the first time. The problem that I am facing is that I have a button on the main uiviewcontroller which by tapping it, it will refresh the container view. This is where the problem is. The outlets in the child controller are nil.
This is how I am trying to all the function in the child controller.
let wcvc = self.storyboard!.instantiateViewController(withIdentifier: "WeatherCurrentViewController") as! WeatherCurrentViewController
wcvc.callJson()
In the child controller the label is like this
#IBOutlet var currentweather: UILabel!
But in the function that is called I get an error of unexpectedly found nil while unwrapping an Optional value when I try to do
print(currentweather)
Anyone have an idea of what I can do to call a function in a view controller that is loaded by segue in a container view and still have the outlets be valid? Please let me know if more info is needed.
Found the solution. I needed to use segues identifiers and not the storyboard. Doing this
private var currentEmbeddedViewController: WeatherCurrentViewController!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let cvc = segue.destination as? WeatherCurrentViewController, segue.identifier == "CurrentWeather" {
self.currentEmbeddedViewController = cvc
}
}
And calling the function in the controller like so
self.currentEmbeddedViewController.callJson()
Was the solution. This question offered the solution. Sorry to waste everyones time. Hopefully, this will help someone else.
The reason why you get an exception is that your currentweather label will get loaded from the storyboard only when the view of that view controller loads. This means, that when you try to call callJson() the view is not yet loaded and thus no IBOutlets are loaded yet as well, meaning they are nil.
I would suggest passing some data to theWeatherCurrentViewController and only on viewDidLoad updating the views. viewDidLoad guarantees that view and all the outlets are loaded and are not nil