I have been having some issues with my prepareForSegue call. Whenever I try to segue to the next view controller. It gets an error and crashes at the point where I am passing the tripLikes to the next view controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toDetailScene") {
//Hooking up places-holder values
let viewController = segue.destinationViewController as! DetailViewController
let cell = sender as! CustomPFTableViewCell
viewController.tripName = cell.nameTextLabel.text!
viewController.tripAuthor = cell.authorTextLabel.text!
viewController.tripLikes = Int(cell.numLikes.text!)!
viewController.tripDescrip = cell.descriptionHolder
}
}
Each of the values that we are passing to are values in the destination view controller.
You're doing a lot of force-unwrapping with Int(cell.numLikes.text!)!. If any of those values are nil, your program will crash.
Why not try something safer, such as an if-let flow:
if let text = cell.numLikes.text {
if let textInt = Int(text) {
viewController.tripLikes = textInt
} else { // Int cannot be constructed from input
viewController.tripLikes = 0
}
} else { // cell.numLikes.text was nil
viewController.tripLikes = 0
}
Related
I have a function that passes in a string to determine what class my destination vc will be once I navigate. I'm also passing data to vc regardless of which class vc ends up being cast as. However, I'm getting an expected error of
VAlue of type 'UIViewController?' has no member ....
since vc hasn't been cast as any subclass yet.
func passAndNavigateResultsFor(surveyName: String){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateInitialViewController()
//Determining which class vc will be cast as
if surveyName == "EFDizzinessSurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFDizzinessSurveyResults
} else if surveyName == "EFHipArthritisSurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFHipArthritisSurveyResults
} else if surveyName == "EFKoosKneeSurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFKoosKneeSurveyResults
} else if surveyName == "EFLEFSSurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFLEFSSurveyResults
} else if surveyName == "EFQuickDASHSurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFQuickDASHSurveyResults
} else if surveyName == "EFNeckDisabilitySurveyTask" {
let vc = storyboard.instantiateViewController(withIdentifier :surveyName) as! EFNeckDisabilitySurveyResults
}
//Data that I want to pass through regardless of which class vc is cast as
if (firstNameResult != nil) && (lastNameResult != nil) {
self.fullName = self.firstNameResult! + " " + self.lastNameResult!
vc.nameText = self.fullName!
}
if painLevelResult != nil {
vc.painLevelText = String(describing: painLevelResult!)
}
if careSatisfactionResult != nil {
vc.careSatisfactionText = String(describing: careSatisfactionResult!)
}
if rateProgressResult != nil {
vc.rateProgressText = String(describing: rateProgressResult!)
}
if therapyGoalsResult != nil {
vc.therapyGoalsText = String(describing: therapyGoalsResult!)
}
if step1Result != nil {
vc.step1Text = String(describing: step1Result!)
}
if step2Result != nil {
vc.step2Text = String(describing: step2Result!)
}
if step3Result != nil {
vc.step3Text = String(describing: step3Result!)
}
if step4Result != nil {
vc.step4Text = String(describing: step4Result!)
}
}
Is there a way to fix this problem, or should I look at a solution like prepareForSegue instead?
What is the exact error being thrown? What member does it not exactly have?
Personally I agree with you and would use prepare for segue like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let yourVC = segue.destination as? YourViewController {
yourVC.painLevelText = painLevelText
}
}
You could find, cast, and prepare the correct VC in there.
If you are having problems with properties not found then you should consider creating a superclass for your VC's to store properties like painLevelText
I am new to swift and am looking for some help with this particular function I am trying to write.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
switch identifier {
case "Show Album":
let albumViewController = segue.destination as! AlbumViewController
let albumImageView = (sender as AnyObject).view as! UIImageView
if let index = index(of: covers, albumImageView) {
let album = Album(index: index)
albumViewController.album = album
}
On the line:
let albumImageView = (sender as AnyObject).view as! UIImageView
Getting the error:
ambiguous use of 'view'
Any help is appreciated.
sender as AnyObject casts sender to type AnyObject. AnyObject does not have a property with the name view, so calling .view on it does not make sense.
I am practicing iOS (Swift) with Firebase. the first viewcontroller retrieves all the records from firebase db and populate the tableView from an array. when the user selects an item from that tableview a new viewcontroller pops up segueing the object from the listView viewcontroller to the detail viewcontroller. data is populated to the fields successfully!
however when i try to update any of the textfield, the moment i switch to another textfield the initial value is restored in the edited textfield.
I have tried to removeAllObservers... but nothing worked. i even removed "import Firebase" and all associated objects and still it restores the initial value.
am i missing any concept here?
this is the code from the ListViewController:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated);
self.activityIndicator.startAnimating();
self.observeIngrdUpdates = ref.observeEventType(.Value, withBlock: { (snapshot) in
self.ingredients.removeAll();
for child in snapshot.children {
var nutrition:String = "";
var type:Int = 0;
var desc:String = "";
var img:String = "";
var name:String = "";
var price:Double = 0.0;
if let _name = child.value["IngredientName"] as? String {
name = _name;
}
if let _nutrition = child.value["NutritionFacts"] as? String {
nutrition = _nutrition;
}
if let _type = child.value["IngredientType"] as? Int {
type = _type;
}
if let _desc = child.value["UnitDescription"] as? String {
desc = _desc;
}
if let _img = child.value["IngredientImage"] as? String {
img = _img;
}
if let _price = child.value["IngredientPrice"] as? Double {
price = _price;
}
let ingredient = Ingredient(name: name, type: type, image: img, unitDesc: desc, nutritionFacts: nutrition, price: price);
ingredient.key = child.key;
self.ingredients.append(ingredient);
}
self.tableView.reloadData();
})
}
and the PrepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as! EditIngredientVC;
if segue.identifier?.compare(SEGUE_EDIT_INGREDIENTS) == .OrderedSame {
destinationVC.ingredient = ingredients[tableView.indexPathForSelectedRow!.row];
destinationVC.controllerTitle = "Edit";
} else if segue.identifier?.compare(SEGUE_ADD_INGREDIENT) == .OrderedSame {
destinationVC.controllerTitle = "New";
}
}
this is the code for populating the fields in DetailViewController:
override func viewDidLayoutSubviews() {
lblControllerTitle.text = controllerTitle;
if controllerTitle?.localizedCaseInsensitiveCompare("NEW") == .OrderedSame {
self.segVegFru.selectedSegmentIndex = 0;
} else {
if ingredient != nil {
self.txtIngredientName.text = ingredient!.name;
self.txtUnitDesc.text = ingredient!.unitDesc;
self.segVegFru.selectedSegmentIndex = ingredient!.typeInt;
self.txtNutritionFacts.text = ingredient!.nutritionFacts;
self.txtPrice.text = "\(ingredient!.price)";
}
}
}
Thank you all for your help.
It's probably because you are putting your textField populating code, in viewDidLayoutSubviews() method.
This method will be triggered every time the layout of a views changes in viewcontroller.
Move it to viewDidLoad() and it should be fine.
The reason that it's being reverted to the previous value is because. You are populating the textField.text from the "ingredient" object. The ingredient will have the same value retained that you passed from previous view controller. Until you mutate it at some point.
And by the way Firebase is very cool I like it too :)
This code is from the locations tableView view controller, where the locations are serialized from a Four Square API and I grab the data, passing it back the view controller where I create an event. The data is serialized correctly, populating the tableView and all, so I won't bother posting that for now, just the segue method to pass the data.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexPath = self.tableView.indexPathForSelectedRow
let item = self.responseItems![indexPath!.row]
var eventVC = CreateEventViewController()
if segue.identifier == "pushBackToEventVC" {
if let venue = item["venue"] as? NSDictionary {
let locationString = venue["name"] as! String
let location = venue["location"]
//get lat/long strings
print(location)
eventVC.updateWithLocation(locationString)
eventVC.updateWithGeoPoint(PFGeoPoint(latitude: locationLatitude, longitude: locationLongitude))
}
eventVC = segue.destinationViewController as! CreateEventViewController
//pass location coordinates
}
//the rest of the segue method
}
The update methods in the crete event view controller, when I put a breakpoint on these methods I can see the data has been passed correctly, and the location (a PFGeoPoint) works okay but the locationString (a string) throws a "Bad instruction error" although it does print it correctly to the console
func updateWithLocation(locationString: String) {
print(locationString)
self.locationLabel.text = locationString
}
func updateWithGeoPoint(venueLocation: PFGeoPoint) {
// print(venueLocation)
self.event?.location = venueLocation
self.eventLocation = venueLocation
print(self.eventLocation)
}
Any ideas? It's basically working but won't update the label with the string although I can see it's been passed correctly. Thanks for the help as always.
Try using this code block instead,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "pushBackToEventVC") {
let detailViewController = ((segue.destinationViewController) as! CreateEventViewController)
let indexPath = self.tableView!.indexPathForSelectedRow!
detailViewController.locationString = venue["location"]
}
}
Im writing a table view controller using an array from Parse. I need to send data through the segue but I dont know why its always returning nil. I will have to send images and text, but for now im just taking the text from the label title1 to insert it into a variable type String named example.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toDetail" {
var detailScene = segue.destinationViewController as! detailViewController
let cell = sender as! UITableViewCell
let indexPath = tableView?.indexPathForCell(cell)
detailScene.example = self.timelineData[indexPath!.row].title1?.text
}
}
For the array I have used:
var timelineData : NSMutableArray = NSMutableArray()
And the function loaddata, that is used with the function viewDidAppear
func loaddata () {
timelineData.removeAllObjects()
var findTimelineData:PFQuery = PFQuery(className: "ii")
findTimelineData.findObjectsInBackgroundWithBlock{
(objects, error)->Void in
if error == nil{
for object in objects!{
let ii:PFObject = object as! PFObject
self.timelineData.addObject(ii)
}
let array:NSArray = self.timelineData.reverseObjectEnumerator().allObjects
self.timelineData = NSMutableArray(array: array)
self.tableView.reloadData()
}
}
}
Try this. It should at least get you to the point where you're grabbing the information from the correct cell. I'm assuming your timelineData array is full of text, so that's how I accessed it, by casting it as a String. If it is full of a different type of object you need to cast it differently.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toDetail" {
if let detailScene = segue.destinationViewController as? detailViewController {
if let indexPath = tableView.indexPathForSelectedRow()?.row {
var object = self.timelineData[indexPath] as! PFObject
var title = object["title"] as! String
detailScene.example = title
}
}
}
}
It could be that the return value from indexPathForCell is returning nil or a bad value. There are quite a few articles about this function being unreliable.
A common suggestion is to use indexPathForRowAtPoint(cell.center) instead.
There is definitely something wrong with your last line of code:
detailScene.example = self.timelineData[indexPath!.row].title1?.text
I assume that self.timelineData array that holds some data.
If your array contain String class you don't need to append .title1?.text part.
If your array contain UILabel class you need change line to
detailScene.example = self.timelineData[indexPath!.row].text
because UILabel have no property called title1.
In general I think this happened because class in self.timelineData array have no property called title1.