Can't UnWrap Optional - None Swift - ios

I assure you that i have checked all the answers prior posting this question on Unwrapping an object, but this thing simply does not seem to work for me. I am simply trying to pass on a text value from my cell tapped to the Label on the next screen.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if(segue.identifier == "detailViewSegue")
{
var DVC:DetailedViewController = segue.destinationViewController as DetailedViewController
let path:NSIndexPath = self.tableView.indexPathForSelectedRow()
var segueRecipeName:String = recipeMgr.RecipeName[path.row] as String
DVC.detailedRecipeLabel.text = segueRecipeName
}
}
The problem occurs at this line -
DVC.detailedRecipeLabel.text = segueRecipeName //Can't UnWrap Optional - None
I know I'm supposed to check the nil value of segueRecipeName before assigning. I do a print check on the console and it clearly is not null. The error occurs only when I'm assigning the value to the 2nd view controller class object. I'm sure this will help others learning Swift :)

DVC.detailedRecipeLabel is nil
Probably it's a IBOutlet that hasn't been loaded yet.
You should add a custom property to your DetailedViewController that will accept your text, save it and then you can assign it to the label in viewDidLoad.
Example:
class DetailedViewController ... {
...
var recipeName: NSString? = nil
...
override func viewDidLoad() -> () {
...
self.detailedRecipeLabel.text = self.recipeName
}
}
DVC.recipeName = segueRecipeName

Related

Having trouble initializing variable

I'm trying to initialize a variable in a view controller before that view controller takes over the view, and it seems no matter how I try to initialize it, it doesn't work and the software runs as if the value is the default value. Part of the problem seems to be the view that contains the variable in question is nil when I try to set the variable's value. I don't know why this is. Any help would be appreciated. Thanks! Here is my code:
override func setStartPosition()
{
if sessionNameIndex != nil
{
if let curSession = ShareData.sharedInstance.sessionDataObjectContainer[sessionNames[sessionNameIndex]]
{
initialValue = YesNo(rawValue: (curSession.currentValue))
if mySessionDisplay == nil
{
mySessionDisplay = SessionDisplayView(frame: self.view.frame)
if mySessionDisplay == nil
{
var shouldneverbehere = 0 //Always goes here!
}
else
{
mySessionDisplay.onView(index: 2, sessionName: sessionNames[sessionNameIndex])
mySessionDisplay.curScene.setStartPosition(newValue: val!)
}
}
}
}
}
This function gets called in the following code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if let destination = segue.destination as? SessionDisplayViewControllerTwo
{
if let myNames = sender as? [String]
{
destination.sessionNames = myNames
destination.sessionNameIndex = 1
destination.setStartPosition()
}
}
}
Let me know if you need more information. Once again, thanks for your consideration of this matter.
A view controller's views have not yet been loaded in prepareForSegue. As #muescha suggests in his comment, you should set properties in prepareForSegue, and then wait for viewDidLoad or viewWillAppear before you try to install them in your views. I'm not sure why your attempt to manually create your SessionDisplayView is failing, but you should not be trying to create views in prepareForSegue in any case, so the solution is "Don't do that."

Swift property nil outside unwindToViewController

To pass data between views, I decided to use a "temporary" object that would act as the data model of my views.
var tempMedecine = TempMedecine()
var xValue = 0
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let dmController = segue.destinationViewController as? JRBDosageMainTableViewController {
dmController.tempMedecine = self.tempMedecine
}
}
#IBAction func unwindToViewController(segue: UIStoryboardSegue) {
if let dosageController = segue.sourceViewController as? JRBDosageMainTableViewController {
self.tempMedecine = dosageController.tempMedecine!
self.xValue = 10
let dosageCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 1, inSection: 0))
dosageCell?.detailTextLabel?.text = String(self.tempMedecine.dosageQuantity!) + " " + self.tempMedecine.dosageQuantityType!
}
}
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if identifier == "saveMedecine" {
print(xValue)
guard tempMedecine.name != nil else {
Common.genericAlertController(self, title: "Error", message: "You need to define a name", preferedStyle: .Alert)
return false
}
guard self.tempMedecine.dosageQuantityType != nil else {
Common.genericAlertController(self, title: "Error", message: "You need to set a quantity", preferedStyle: .Alert)
return false
}
}
else {
return true
}
return false
}
This is some of my code from the "index" viewController where I need to tackle validation.
As you can see all of my viewControllers have a property named tempMedecine. I pass it around and update the data if needed.
The problem is that self.tempMedecine.dosageQuantityType returns nil in the shouldPerformSegueWithIdentifier method but isn't returning nil in the unwindToViewController method.
I figured there could be two instances of my TempMedecine object, but that's not the case. I also thought there might be a problem with the way I pass the tempMedecine variable between my viewControllers but the property tempMedecine.name is effectively transfered, the only difference is that this property is set in the same viewController where I want to implement validation :
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
self.tempMedecine.name = textField.text
return true
}
It's really looking like I'm working with two different scope. As soon as I leave the unwindToViewController method, I would get back to another scope where the tempMedecine variable isn't updated.
But the weird part is when I use a simple variable like xValue. If I update its value in the unwindToViewController method I get the correct value in shouldPerformSegueWithIdentifier
What am I missing? Thanks for your help.
Okay, I fixed it. What happened was that I implemented some code to reset the dataSource which is tempMedecine if the user decided to click on the Back Button in the navigation bar :
if self.isMovingToParentViewController() {
tempMedecine?.dosageQuantity = nil
tempMedecine?.dosageQuantityType = nil
}
The thing is, I never thought the issue could come from this as I can use the tempMedecine data to set the value in my tableView after unwinding to the index viewController but I totally missed the part when object are passed my reference.

Property value prints but when assigned to label it shows nil

Currently working with two view controllers and a swift file dealing with the details of a store such as the phone number. There is a main ViewController and a DetailsViewController.
I currently acquire data from google places api and am able to successfully store the values in a PlaceDetails Class. Testing out the data - I am able to print to the console. However, when I try to assign a value taken from the API to a UILabel the application crashes and shows that the value of the property is nil. I am not sure why this is the case. I feel in the two view controllers I am instantiating the PlaceDetails class correctly and accessing it's properties correctly but there is something I am not aware of that is going wrong.
class ViewController: UIViewController
{
let placeDetails = PlaceDetails()
let detailsVC = DetailsViewController()
func tapLabel( sender: UITapGestureRecognizer )
{
// print statement successfully prints out the stored value as - Optional("1 888-555-5555")
print(placeDetails.phoneNumber)
// assigning value to label causes a crash stating value is nil
detailsVC.phoneNumberLabel.text = placeDetails.phoneNumber!
self.performSegueWithIdentifier("showDetailsVC", sender: self)
}
}
class DetailsViewController: UIViewController
{
#IBOutlet weak var phoneNumberLabel : UILabel!
let placeDetails = PlaceDetails()
override func viewDidLoad()
{
super.viewDidLoad()
//This approach does not cause a crash but outputs nil to the console for both the print statement and the assignment statement
print(placeDetails.phoneNumber)
phoneNumberLabel.text = placeDetails.phoneNumber!
}
}
class PlaceDetails
{
override init()
{
super.init()
}
var phoneNumber : String? //viewcontroller actions give this class property its value
}
You need to assign placeDetails to your destination view controller in prepareForSegue. I know you aren't doing this as you have created placeDetails as a let constant rather than a variable so it can't ever change from the empty PlaceDetails you originally assign.
You should declare it as an optional variable and then unwrap it properly when you use it;
class ViewController: UIViewController
{
let placeDetails = PlaceDetails()
func tapLabel( sender: UITapGestureRecognizer )
{
self.performSegueWithIdentifier("showDetailsVC", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showDetailsVC") {
let destVC = segue.destinationViewController as! DetailsViewController
destVC.placeDetails = self.placeDetails
}
}
}
class DetailsViewController: UIViewController
{
#IBOutlet weak var phoneNumberLabel : UILabel!
var placeDetails: PlaceDetails?
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
if let placeDetails = self.placeDetails {
if let phoneNumber = placeDetails.phoneNumber {
self.phoneNumberLabel.text = phoneNumber
}
}
}
}
You can't use the value in viewDidLoad as this method will execute before the property has been set; the view controller is loaded before prepareForSegue is called, so viewWillAppear is a better place.
Try to cast your phoneNumber in a string.
detailsVC.phoneNumberLabel.text = String(placeDetails.phoneNumber!)
Also, the nil value could come from the encoding method of the response of the API.
EDIT
I think you have to set the text of your UILabel in the viewDidLoad() method of your showDetailsVC. Declare a string variable in showDetailVC, and then pass your placeDetails.phoneNumber variable to the string you just declare. (Instead of directly set the text in the tapLabel() method). Then in your
showDetailVC set the text to your UILabel in the viewDidLoad()

Passing data between controllers - unexpectedly found nil while unwrapping an Optional

I am attempting a very simple task of passing data between two view controllers. I have control-dragged the label into the proper class and allowed the segues to populate with the correct data. Upon clicking the row, the prepareForSegue action is as:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "individualChat" {
if let indexPath = tableView.indexPathForSelectedRow {
let friend: Friend
friend = mappedFriends[indexPath.row]
let controller = segue.destinationViewController as! IndividualChatController
controller.friendChat = friend
}
}
}
and into the residing view controller:
import UIKit
class IndividualChatController: UIViewController {
#IBOutlet weak var anotherTestLabel: UILabel!
var friendChat: Friend! {
didSet {
configureView()
}
}
func configureView() {
if let friendChat = friendChat {
anotherTestLabel.text = friendChat.name as? String
}
}
}
Yet, upon clicking the row, the error appears:
fatal error: unexpectedly found nil while unwrapping an Optional value
on line:
anotherTestLabel.text = friendChat.name as? String
How can this be fixed?
Additional Screen Capture:
When you execute some code in prepareForSegue the next view is not loaded yet so all your outlets are still set to nil; because of this when you try to implicitly unwrap the content of anotherTestLabel at
anotherTestLabel.text = friendChat.name as? String
you get that error.
You can check if your label has been loaded and only if that's the case set its text using
anotherTestLabel?.text = friendChat.name as? String
and then manually calling configureView() in viewDidLoad() of IndividualChatController to proper load the label.
The added ? will check if your label is nil, if so nothing will be done, else it will proceed unwrapping the label and setting the text.

Error "cannot assign a value of type" in prepareForSegue method (Swift, Xcode 6)

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

Resources