UITextField always results in nil - swift

I'm trying to get the information of a UITextField and then reuse that data from the UITextField with swift 2.0 and Xcode 7. But every time I run the app, the app crashes and says:
fatal error: unexpectedly found nil while unwrapping an Optional value
even though there is something in the textfield.
Someone knows how to solve this problem?
This is how my code looks:
#IBOutlet weak var entryAmount: UITextField! //TextField declaration
#IBAction func saveNewButtonTapped(sender: UIBarButtonItem) {
//update overall amount
let amount: String? = self.entryAmount.text! //Throws the error at this point
self.viewController.currentValue += amount
}
In another function, I wrote the same thing ("let amount: String? = entryAmount.text!") and when I printed "amount", it showed the right result. But as soon as I tried to use it further, "amount" was always set to nil, even tough it always printed the right result in the beginning.
I encounter the same thing with DatePicker, Switches and updating Button texts.
Someone knows something to help me? - Thanks
Btw I'm pretty new to swift and Xcode.
Update: Could it be because the TextField is in a ContainerView?
Update Two: I'm pretty much sure the problem is because of the ContainerView. I tried a TextField that isn't in a containerView and didn't get the error, it worked perfectly fine.

Please check in your Interface Builder that the UITextField is properly linked to your "entryAmount" IBOutlet. It might be the case that they are not properly connected and that's why the value is nil at runtime.

I could be wrong but what it seems like from your question is you're having trouble with scoping. Any variables you declare in a function are scoped only to that function.
Declaring amount in saveNewButtonTapped means amount is only set in that function. Using amount in another function will result in amount being nil. If you want to use variables between functions you need to declare them outside of a function.
In the example I have the var runningAmount. In the example, if I press the button that calls pressAnotherButton, I get the same fatal error you get because I'm unwrapping self.runningAmount before it's been set. But if I press the button that calls saveNewButtonTapped, even with nothing in the textfield, then press the button that calls pressAnotherButton, I get the output in the photo.

Related

Swift, How to use data passed back from VC in other functions?

I'm having trouble accessing and using the variable the value I got from a popover
First time ever asking a question on here and fairly new to programming so please be gentle. My program has a popup that displays a date for the user to select, and then that date is passed back to the main view controller. I tested this aspect to make sure the data was being passed back to the vc by getting the program to display the date in a label using callbacks and delegation (I tested both ways), and it worked fine, but what I'm trying to do is use that value taken from the popup, placing it into a variable, and using it for further calculations in other functions.
I tried to take change the protocol function have a return value from originally (value: String) -> (), to (value: String) -> (String)
but then realized this wouldn't work when I try to access that function from say the viewDidLoad function I don't have an input value
like if I did this inside of viewDidLoad
date = popupValueSelected(value: ???) // throws an error because it doesn't know about the delegate
This is my delegate protocol code:
protocol PopupDelegate {
func popupValueSelected(value:String)
}
Here is the code used in my main view controller to get the Data from the popover, which all works fine
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let popup = segue.destination as! DatePopupViewController
popup.delegate = self
}
func popupValueSelected(value: String) {
date = value // how to access this value from somewhere else??
}
All I want to do is use the value that I from the popover in another separate function. How would I pass that value somewhere else if I can't return it? I've sifted through answers on here and saw someone ask a similar question, but the first answer I saw was to use delegation, but no further explanation. I don't want to display that value or use it right away, I only want to use it for another calculation, that will be displayed when the user clicks a different button.
I'm sorry if this doesn't make sense as I'm having a difficult time explaining the issue, hence the throwaway account, though I feel like there's something so simple that I'm missing.
I appreciate all the feedback I can get!
Unless I’m missing something you seem to be 90% of the way there. You’ve got popupValueSelected getting a value. If you store the value off to a class level variable you can then use it later. Let me know if I’m not understanding your issue fully.

Swift performance on optional UI elements

Setting up a UILabel in Swift I can do the following
#IBOutlet var wLabel: UILabel!
or
#IBOutlet var wLabel: UILabel?
Setting the text I can either do
wLabel.text = "..."
or, for the latter do
wLabel?.text = "..." // with a question mark for the optional
Keeping them optional will help for the case when they are unexpectedly nil as it will just skip this call then and go ahead with the code. Having them declared with the ! would crash the app if the label was nil.
Now why would you not make everything optional? The only reason I could think of would be for better performance. Should I stay away from having them optional if my app has a lot of UI elements so them being optional would mean a disadvantage regarding performance? I wasn't able to find any information on this anyhere.
Using ? in your Outlet will make your code untracable
Crashes are very good in some scenarios, because if no crash is there then it becomes super difficult to trace even small error.
Consider the examples of #IBOutlet with !:
#IBOutlet var wLabel: UILabel!
wLabel.isEnabled = true
Just remove the connection of your Outlet label from your storyboard and run the app, your app will crash on wLabel.isEnabled = true. Since you got a crash so you can got to your storyboard see whether the connection is proper or not. In case there is no connect you add it and damn! you solved the problem easily.
Now consider the examples of #IBOutlet with ?:
#IBOutlet var wLabel: UILabel?
wLabel?.isEnabled = true
Do the same thing, just remove the connection of your Outlet label from your storyboard and run the app, your app won't crash at all. You won't be able to know the error, hence making your code a mess and untracable.
Apple guys were very aware of optional thing, they did force unwrapping of #IBOutlet for a reason. And of course there is no performance difference between ! and ?
If you're setting something up as an outlet it's set up as a force unwrapped optional (with exclamation mark !) because Swift requires your classes to have all of their properties initialized when the object is constructed (i.e. init method is called). Outlets are not created during object construction but rather assigned later when the xib or storyboard data is loaded into your component. Force unwrapped optionals are basically a way to say that you guarantee that the property will be initialized after object's init is called and before they're used.
There are no performance gains to using either of these. An Optional? type means that the property can either be nil or have a value. A force unwrapped optional ! means that the property is guaranteed to have a value when it is used. Upholding this is up to the developer and using such property if its value is nil will result in a crash.

Though I did optional binding, I got error “fatal error: unexpectedly found nil while unwrapping an Optional value"

I received data from my application server, and then assign that data to ios's object(articles).
And using that object(articles), I save values to cell's label in tableView.
After that, when user click the cell of tableView, this app move to another ViewController(NoticeArticleVC). Before moving, I assign value of object(articles) to that ViewController's variable like below code.
However, as usual, I did optional binding using 'if let' statement. But I got error as if I didn't do optional binding.
Though I cleaned build folder, and then rebuilded, it didn't work.
Please let me know what's wrong with my code.
You've instantiated the new ViewController, but I don't think titleLabel will be set until the view has loaded. You will need to present the new view controller and then set the label. Or better, set a variable on the new ViewController and only set the label field from within that VC code (e.g. in/after viewDidLoad).

Swift word count fatal error [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am working on a word count function in textViewDidChange. As soon as I type it crashes. When I paste in a sentence, the debugger shows it is getting the word count, but it is crashing when adding the count to the button title with a fatal error: unexpectedly found nil while unwrapping an Optional value.
func textViewDidChange(textView: UITextView) {
let wordCount = textView.text.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).count
let words = String(format: "%d", wordCount)
countButton.title = "\(words)"
}
Make sure your countButton is non-nil (check the outlet connection).
Also, the variable in your string interpolation, count, does not seem to be defined - maybe an ivar that is still nil?
Edit:
As it turns out, your countButton is in fact nil and programmatically created. I suspect a definition like so:
weak var countButton : UIButton!
As well as an initialization like so:
self.countButton = UIButton()
The problem is then, that the weak modifier tells the system to not hold ownership of the object. Thus, it immediately gets deallocated after creation.
Try this instead:
let button = UIButton()
self.view?.addSubview(button)
self.countButton = button
The variable wordCount also has a warning saying it was never mutated, consider changing it to let. I assumed var was the was the way to go since the count would change
The count might change. But the value of the variable wordCount will never change, at least in the code you show. The only thing you ever do with it, having created it, is print it. Thus, it should be a let variable, as the compiler suggests.

Swift View Controller Downcasting

I thought the following would populate my home variable with my HomeViewController
var home = self.parentViewController!.parentViewController! as HomeViewController;
Instead I get the following compile error 'Use of undeclared type HomeViewController' although it definitely exists and appears in the auto complete popup.
Often XCode6 displays the wrong error message. Is this an instance variable? It may be that parentViewController isn't set at init time (the fact that it's an implicitly unwrapped optional strongly suggests this). If this is in a function, I'd do this in an if let statement to give us a better sense of what's going on. Something like:
if let homeVC = self.parentViewController?.parentViewController as? HomeViewController {
self.home = homeVC
}
This would give us at least a better opportunity to debug. Two !s in a row maybe means you're not being totally respectful of what those declarations are trying to tell you.
The cause of this error was actually coming from a bug in xcode 6 rather than any kind of syntax error. It was related to this: Xcode 6 Strange Bug: Unknown class in Interface Builder file
I was able to fix this by clearing the projects derived data and build and restarting my machine.
I had faced the same problem while doing an unwind segue and trying to downcast the sourceviewcontroller. I bang my head for more than 30mins and then I realized it was fairly simple and bit crazy, I had all my files except this viewcontroller added to the Tests target and after adding this viewcontroller to the Tests target, everything worked Tada!! I m saved.