Before I begin, let me say that I have taken a look at a popular post on the matter: Passing Data between View Controllers
My project is on github https://github.com/model3volution/TipMe
I am inside of a UINavigationController, thus using a pushsegue.
I have verified that my IBAction methods are properly linked up and that segue.identifier corresponds to the segue's identifier in the storyboard.
If I take out the prepareForSegue: method then the segue occurs, but obviously without any data updating.
My specific error message is: Could not cast value of type 'TipMe.FacesViewController' (0x10de38) to 'UINavigationController' (0x1892e1c).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
if segue.identifier == "toFacesVC" {
let navController:UINavigationController = segue.destinationViewController as! UINavigationController
let facesVC = navController.topViewController as! FacesViewController
facesVC.balanceLabel.text = "Balance before tip: $\(balanceDouble)"
}
}
Below is a screenshot with the code and error.
side notes: using Xcode 6.3, Swift 1.2
A couple of things:
1: change your prepareForSegue to
if segue.identifier == "toFacesVC" {
let facesVC = segue.destinationViewController as! FacesViewController
facesVC.text = "Balance before tip: $\(balanceDouble)"
}
2: add a string variable to your FacesViewController
var text:String!
3: change the FacesViewController viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
balanceLabel.text = text
}
The reasons for all the changes: the segue destinationViewController is the actual FacesViewController you transition to -> no need for the navigationController shenanigans. That alone will remove the "case error", but another will occur due to unwrapping a nil value because you try to access the balanceLabel which will not have been set yet. Therefore you need to create a string variable to hold the string you actually want to assign and then assign that text in the viewDidLoad - at the point where the UILabel is actually assigned.
Proof that it works:
4: If you want display two decimal places for the balance you might change the String creation to something like (following https://stackoverflow.com/a/24102844/2442804):
facesVC.text = String(format: "Balance before tip: $%.2f", balanceDouble)
resulting in:
Related
Tell me, please, I'm trying to solve the problem of transferring an instance of a class to another controller using the Realm database.
I have a main controller that stores objects according to the model the following data:
class Route: Object {
#objc dynamic var routeImage: Data?
#objc dynamic var routeName: String?
#objc dynamic var numberOfPersons = 0.0
#objc dynamic var dateOfDeparture: String?
#objc dynamic var dateOfArrival: String?
let placeToVisit = List<Place>()
let person = List<Person>()
}
In the controller to which I need to transfer this data, I created
var currentRoute: Route!
In the Storyboard, I specified the identifier "showDetail" from the controller cell to the UITabBar, and in the main controller, I created a method:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
guard let indexPath = tableView.indexPathForSelectedRow else {return}
let newPlaceVC = segue.destination as! InformationViewController
newPlaceVC.currentRoute = routes[indexPath.row]
}
}
Error I got:
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Could not cast value of type 'UITabBarController' (0x111ed8b10) to 'Organizer_Tourist.InformationViewController' (0x108dd0a70).
2019-10-07 14:30:35.626853+0800 Organizer Tourist[5467:2618892] Could not cast value of type 'UITabBarController' (0x111ed8b10) to 'Organizer_Tourist.InformationViewController' (0x108dd0a70).
(lldb)
But it is not valid, the application crashes by tap on the cell. I suppose this would work if there was not a tabBar, but a regular table, view controllers. I was looking for solutions and all I came across was implementation through singleton. Now I have a lot of questions, but will this really be the right decision? People say this violates the "modularity" of the application and carries its own problems. The question is how is this done through singleton? What to consider, where to start? Which method is worth editing?
Error said what is happening:
Could not cast value of type 'UITabBarController'
You are trying to cast segue.destination to typo InformationViewController which is not.
If you embed your InformationViewController in UITabBarController so you need to cast to your UITabBarController rather than InformationViewController.
Try something like this:
if segue.identifier == "showDetail" {
guard let indexPath = tableView.indexPathForSelectedRow else { return }
let tabBarController = segue.destination as! UITabBarController
UserSelectedRoute.shared.selectedRoute = routes[indexPath.row]
}
If you want to pass current selected route to InformationViewController you can create singleton object which will be hold current route
final class UserSelectedRoute {
private init() { }
static var shared = UserSelectedRoute()
var selectedRoute: Route?
}
And then in your InformationViewController you can have something like:
var currentRoute = UserSelectedRoute.shared.selectedRoute
Hope this will help you!
Using a button to collect a phone number and then reading and storing the phone number under the button function.
#IBAction func viewRewardsButtonTapped(_ sender: UIButton) {
view.endEditing(true)
// Validate format
let phoneNumberInput = phoneInput.text
}
Is there a better way to store the phone number phoneNumberInput and get it to another UIViewController?
I currently can't get the other UIViewController to recognize the variables stored under the #IBAction function.
You could use UserDefaults:
// Set phone number
UserDefaults.standard.set(phoneInput,text, forKey: "phoneNumber")
// Get phone number
UserDefaults.standard.string(forKey: "phoneNumber")
Or if you want to segue at the same time that you´re clicking the button use this:
self.performSegue(withIdentifier: "showVC2", sender: phoneNumber.text)
override func prepare(for segue: UIStoryboardSegue, sender: Any!) {
if (segue.identifier == "showVC2") {
if let phoneNumber = sender as? String {
let vc = segue.destination as! YourSecondVC
vc.phoneNumber = phoneNumber
}
}
}
So you basically create the segue and declare a variable for phoneNumber in your second VC so that you can pass the value to it.
Your phoneNumberInput variable is only stored in the scope of your action handler method viewRewardsButtonTapped, so once this method is left the value is lost. You should add a member variable (var phoneNumber: String?) to your class and use this for storing the value. Then, when you open the next view controller, you can pass the value in as a parameter.
If you are using storyboard segues (which I assume), you have to implement performSegue withIdentifier, cast the destination view controller to the concrete type and set the value (e.g. targetVC.phoneNumber = self.phoneNumber).
I'm trying to pass a string to a second view controller. The string is the title of the new view controller.
To pass the string I can use 2 solutions and both solutions work correctly but for me is not so clear the difference. Can someone explain me the differences?
Here the first solution:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "settime") {
let svc = segue.destinationViewController as! timeSetting;
//Assign the new title
svc.toPass = "New Title"
}
}
Here the second solution:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "settime") {
let svc = segue.destinationViewController as? timeSetting;
//Assign the new title
svc!.toPass = "New Title"
}
}
The variable toPass is defined in this way in the second viewController:
var toPass:String = "Title"
Both of your code is working and it works in the same way.
The only difference is about the optional casting.
Optional in Swift
Both solutions will perform the same action. In my opinion, the first solution is preferred because it express your intent more precisely.
By stating let svc = segue.destinationViewController as! timesetting you state that the destination view controller is certain to be of the type timesetting.
The second form tests to see if the destination view controller is of the type timeSetting. If it is, then the variable svc will have a non-nil value.
If you were to define another segue of the same name that presents a different type of view controller, then both solutions will fail; the first one on the as! clause and the second one when you try to unwrap svc!, which would be nil.
They are the same.
If there is a difference, it is the time of unwrap the optional value. In the first solution, the type of svc is timeSetting. In the second solution, the type of svc is timeSetting?.
Both will work but in my opinion the best way is to unwrap the optional like the following:
if let svc = segue.destinationViewController as? timeSerting { svc.toPass = "xx" }
I have been searching every where for a solution but i can't find it and when i look at my code and others it looks as it should be looking.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "helpUpdateProfile" ){
var detailVC = segue.destinationViewController as DetailVC;
detailVC.toPass = "help"
}
}
It seems to be just on the line that says
var detailVC = segue.destinationViewController as DetailVC;
DetailVC is getting the error, i have no idea what type to declare this, also i have not find any one doing that in this code. I would really like to know what type to declare it.
i am using ios7.1 and 8+ for this app with xcode 6.x latest stable version
First you should post the error message, second be sure that DetailVC is selected in class of your viewController
You will either need to force the cast with:
var detailVC = segue.destinationViewController as! DetailVC
Notice the ! after the as.
Or you can do:
if let detailVC = segue.destinationViewController as? DetailVC {
detailVC.toPass = "help"
}
Notice the ? after the as.
segue.destinationViewController returns a UIViewController. What you are doing with the "as" is downcasting the UIViewController to your subclass of UIViewController. The Swift compiler is not able to determine if a downcast between a class and one of its subclasses will succeed. If you know with absolute certainty the type destinationViewController, you can force the downcast with as!. However, if the downcast fails at runtime, your application will crash. The safer option is to use optional binding and if let with as?. For more information you can read about as on the Apple Swift Blog
I just want to make a segue by an example here http://www.codingexplorer.com/segue-uitableviewcell-taps-swift/
But when I made this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == blogSegueIdentifier {
if let destination = segue.destinationViewController as? specialitiesViewController {
if let cellIndex = tableView.indexPathForSelectedRow()?.row {
destination.formuleName = formulesList[cellIndex]
}
}
}
}
Appeared error called:
cannot assign a value of type '(Formules)' to a value of type String"
this is a class which contents a data for formuleList
formuleList is an array with a list of cell names
how to remove error?
Thank u for your help.
The way that this segue block works is you are basically telling the UI that I'm going to segue to the next view controller
if let destination = segue.destinationViewController as? specialitiesViewController - says that the ViewController we are going to is of custom type specialitiesViewController
My assumption would be that in your specialitiesViewController you have a variable called forumlaName that is of type String and that your formulesList is of type [Formules] - and as such this assignment is invalid.
You are trying to assign a specific Formules to a String and thus occurs your error.
Fix choices would be to make sure the type Formules implements one of the String protocols such as Printable that allows it to be represented as a string. Alternativley perhaps you have something like a name variable inside that is a string
Depending on the version of Swift you are using you could do something like:
extension Formules : Printable {
override public var description: String {
return "TEST"
}
}
but with out more actual code info i can't tell you if this will actually work