EXC_BAD_INSTRUCTION when textFields are empty - ios

A big n00b here :-)
I made my first app for IOS and got everything working as long as all text fields are filled. This app is a simple calculation app and I need some help making sure that the app does not close down when fields are empty.
This is my code when a simple Calculation button is pressed.
class ViewController: UIViewController {
#IBOutlet weak var panelWidthTextField: UITextField!
#IBOutlet weak var panelHightTextField: UITextField!
#IBOutlet weak var panelsWideTextField: UITextField!
#IBOutlet weak var panelsHightTextField: UITextField!
#IBOutlet weak var panelPitchTextField: UITextField!
#IBOutlet weak var resultWithLabel: UILabel!
#IBOutlet weak var resultHightLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func calculatePressButton(sender: AnyObject) {
let w = Double(panelWidthTextField.text!)
let sw = Double(panelsWideTextField.text!)
let pi = Double(panelPitchTextField.text!)
let sizew = SizeWidthModel(pw:w!,psw:sw!,ptc:pi!)
resultWithLabel.text=String(sizew.width())
let h = Double(panelHightTextField.text!)
let sh = Double(panelsHightTextField.text!)
let sizeh = SizeHightModel(ph:h!,psh:sh!,ptc:pi!)
resultHightLabel.text=String(sizeh.hight())
}
}
This is my problem.
Hope someone can point me in the right direction.
Edit:
As I am a complete n00b at this coding I need som more help understanding this. I have tried adding various solution with no luck. I am trying to get a message to pop up when user leave fields empty, because the calculation need all fields filled in.
If someone have time to guide me that would be appreciated :-)

Took me a while to figure out optionals, too, but hopefully this explanation helps:
When converting from a String (which is what panelWidthTextField.text is) to a Double, Swift doesn't know if the String is valid or not. Since it might be valid or it might not contain a valid value (is nil), then it's an optional, String?, which can contain a valid String or which can be nil. But just because it can be nil doesn't mean that you can use nil in your code.
The "!" says "use the data in this variable, even if it's nil, because I don't think it's nil." Problem is, if it IS nil, then Double(nil) would crash your app.
If let (there is also an "if var") will say "look into (unwrap) this optional value. If it works, do what's in the first set of braces (which is a let or var assignment), otherwise do what's in the second set of braces.
if let w = Double(panelWidthTextField.text!) {
// you're good to go
} else {
// give the user instructions on how to fix the error.
}
The nil coalescing operator may also help. It reads like this:
// Unwrap a and look at it. If it a isn't nil, then use it, if it is nil, then use default value b
a ?? b
If you wanted to put in a default value (like zero if you need a valid numeral), try:
var w = Double(panelWidthTextField.text!)?? 0

Simply check to see if the user has entered text. In the function, put something like this
if myTextField.text != "" {
//rest of the code
}
Hope this helps.

Related

Adding multiple textfield to firebase using swift

Image of my view controller:
This is my code
class AddViewController: UIViewController {
#IBOutlet weak var questionField: UITextField!
#IBOutlet weak var correctAnswer: UITextField!
#IBOutlet weak var optionA: UITextField!
#IBOutlet weak var optionB: UITextField!
var ref: FIRDatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboard()
}
#IBAction func createQuestion(_ sender: Any) {
ref = FIRDatabase.database().reference(fromURL: "https://******.firebaseio.com/")
if questionField.text != "" && correctAnswer.text != "" && optionA.text != "" && optionB.text != ""
{
self.ref?.child("Questions").setValue(["Question": questionField.text, "CorrectAnswer": correctAnswer.text, "OptionA": optionA.text, "OptionB": optionB.text])
questionField.text = ""
correctAnswer.text = ""
optionA.text = ""
optionB.text = ""
}
else
{
print("Missing fields")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is my goal in Firebase JSON:
My code is working but it replaces(ofc). Is my approach correct in saving questions so that in retrieving it will be easy? Could you give me idea how to save my questions?
First of all you must be using a pretty old version of Firebase if you are creating a database reference like that. For a while now (almost 6 months?) the correct way to create a reference to your database is
var ref: FIRDatabaseReference!
override func viewDidLoad(){
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
And in order for this to work you must download the GoogleService-info.plist file for your firebase project and add it to your Xcode project.
As far as your database structure goes...
What you have in your code is not going to produce what you are aiming for in the picture above. What you have in your code will produce this...
In order to produce data structured in the way you have pictured above you need to do this...
ref.child("Questions").child("Question1").setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
then for question 2...
ref.child("Questions").child("Question2").setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
and then your JSON will look like this ...
Note that I had to add the "Question" key as a child value under the "Question1" node in order to set the text for that question as its value.
Furthermore, if you are not able to increment Question1 followed by Question2... and so on, then you can use Firebase's method .childByAutoId like this for every question and Firebase will automatically generate a unique child id for that node...
ref.child("Questions").childByAutoId().setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
the result will look similar to this...
Hope this helps, let me know if you have further questions
Since setValue() will override the whole content of Questions node.
U should create a child before upload the question to firebase.
ref.child("Questions").childByAutoId().setValue(...)

Saving an integer in core data

Overview
I need to save several TextFields into CoreData, but only the first one (Seen as pickerView below) saves and prints correctly. The others do not save correctly, for instance, when I try to save the integer ones, I get an error saying that they cannot take a String, which makes sense. I just cannot find a way to fix the integer-string issue. The other error occurs when I attempted to cast everything as a string ( mainly because I won't need to do any arithmetic on it, so it doesn't matter ), and it just gives me a breaking point in the saveButton function.
What I would like to know
What I ultimately need is the ability to save all of these TextFields into CoreData so that I can later retrieve them. I appreciate the help in advance. Thank you!
NOTE
I am including the entire ( or most of ) the ViewController.swift file so that you can see how I am declaring things and then how they are being called. The code in question is located in the saveButton action at the bottom of the code block.
CODE
#IBOutlet weak var locationOfMachine: UITextField!
#IBOutlet weak var engineHours: UITextField!
#IBOutlet weak var YOM: UITextField!
#IBOutlet weak var serialNo: UITextField!
#IBOutlet weak var modelName: UITextField!
#IBOutlet weak var pickerTextField: UITextField!
var pickOption = ["Wirtgen","Kleeman","Hamm","Vögele"]
override func viewDidLoad() {
super.viewDidLoad()
var pickerView = UIPickerView()
pickerView.delegate = self
pickerTextField.inputView = pickerView
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
#IBAction func saveButton(sender: AnyObject)
{
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext
var entity1 = NSEntityDescription.insertNewObjectForEntityForName("UsedInfo", inManagedObjectContext:context) as NSManagedObject
entity1.setValue(pickerTextField.text, forKey: "product")
entity1.setValue(modelName.text, forKey:"modelName")
entity1.setValue(serialNo.text, forKey:"serialNo")
entity1.setValue(Int(YOM.text!), forKey:"yom")
entity1.setValue(engineHours.text, forKey:"engineHours")
entity1.setValue(locationOfMachine.text, forKey:"location")
print(entity1.valueForKey("product"))
print(entity1.valueForKey("modelName"))
print(entity1.valueForKey("serialNo"))
print(entity1.valueForKey("yom"))
print(entity1.valueForKey("engineHours"))
do {
try context.save()
}
catch {
print("error")
}
}
EDIT
Upon trying to save everything as just a string, since i only need to retrieve it, I run into this issue:
entity1.setValue(pickerTextField.text, forKey: "product")
entity1.setValue(modelName.text, forKey:"modelName")
entity1.setValue(serialNo.text, forKey:"serialNo") <-Thread1:Breakpoint1.1
entity1.setValue(YOM.text, forKey:"yom")
entity1.setValue(engineHours.text, forKey:"engineHours")
entity1.setValue(locationOfMachine.text, forKey:"location")
print(entity1.valueForKey("product"))
print(entity1.valueForKey("modelName"))
print(entity1.valueForKey("serialNo"))
print(entity1.valueForKey("yom"))
print(entity1.valueForKey("engineHours"))
I also get "(lldb)" in the debugger window.
I'll just show you how to get int from string. Use it accordingly:
var aString = "0000" // var aString = textField.text!
var numFromString = Int(aString)
You can assign the text field to aString and convert it to Int like i showed you.
For things that don't need arithmetic, define them as strings in Core Data. For other numbers, it should work to do as you have with Int(YOM.text!).
However, I suggest that you create a managed object subclass for "UsedInfo" so that you can work directly with its properties instead of using setValue:forKey:. The benefit of a subclass is that it will show you data types explicitly.
Validate all textfields before trying to store,set the appropriate keyboard for each textfield and provide the valid character set for each textfield.
For Example:
YOM text field : Use Keyboard with only integers.
Valid character set are 0 to 9
And validation for min and max if applicable.
If any of the validation criteria fails ,throw an alert to input valid data.
I guess this solves your issue.

Use of unresolved identifier when creating a string

I am very new to swift, but i can work with javascript and php so thought this would make sense to me. I have read so many posts on this topic but non really explain mine. I have the following code which is pretty straight forward. I have several text fields with login information to pass on to php. But when i try to use the var from a function it is not possible. So i figured that out but when i try to redefine the vars outside of the function with different var i am still keep getting the error. This is the code so far
import UIKit
class RegisterPage: UIViewController, UITextFieldDelegate{
#IBOutlet weak var userEmailTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var userPasswordConfirmTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func registerTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userConfirmPassword = userPasswordConfirmTextField.text
// check for empty fields
if(userEmail.isEmpty || userPassword.isEmpty || userConfirmPassword.isEmpty)
{
// Display alert message
displayMyAlertMessage("Alle velden gelieve invullen");
return;
}
//Check if passwords match
if(userPassword != userConfirmPassword){
// Display alert message
displayMyAlertMessage("Wachtwoorden komen niet overeen");
return;
}
}// end of registerTapped button
// send data to server side
static var urlConn: NSURL = NSURL(string: "http://xxxxxxxxx")!
var request: NSMutableURLRequest = NSMutableURLRequest(URL:urlConn);
var credLogin = "email=\(userEmail)&password=\(userPassword)"
the following line is giving the unresolved identifier error
var credLogin = "email=\(userEmail)&password=\(userPassword)"
i have tried so many different things, but i can't move the var in the function outside of it, and i have had also in other code blocks errors like this, i really would like to know how this works in swift.
Thanks
The variables userEmail and userPassword are declared within the scope of the registerTapped method. They are not visible outside this method.
Either put the line
var credLogin = "email=\(userEmail)&password=\(userPassword)"
in the method or declare the variables as instance variables right after IBOutlet declarations.
The code to send data to server side must be also executed within a method.

Initialize object in parse

I am trying to implement a like feature. I have a label and a button. If the button is pressed it should add one vote to Parse and the label would retrieve the number of votes. However it does not work with my code. It looks like I need to initialize parseObject but I don't know how to. my code for the cell is below. Thank you. I have been stuck for this problem for days.
import UIKit
import ParseUI
import Parse
var parseObject:PFObject?
var votes = [PFObject]()
class NewCollectionViewCell: UICollectionViewCell {
var parseObject = PFObject(className: "Posts")
#IBOutlet weak var postsImageView: PFImageView!
#IBOutlet weak var postsLabel: UILabel!
#IBOutlet weak var votesLabel:UILabel?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
postsLabel.textAlignment = NSTextAlignment.Center
}
#IBAction func vote(sender: AnyObject) {
if (parseObject != nil) {
if let votes = parseObject!.objectForKey("votes") as? Int {
parseObject!.setObject(votes + 1, forKey: "votes")
parseObject!.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "\(votes + 1) votes"
}
else {
parseObject!.setObject(1, forKey: "votes")
parseObject!.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "1 votes"
}
}
}
}
First of all, you have implement you target method. I am not sure whether it will save the object or not when you pass in nil. For making it consistent, you better include target and selector because it will also tell you whether the object is saved successfully. You can also go to the Parse dashboard to check whether it's saved successfully or not.
And yes, you have not instantiate your object. Otherwise, your if-else statement just got executed and did nothing. If you try to debug it, the parseObject is actually nil. In Parse, there are several ways to do and docs provides you everything: https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/objectWithClassName:

NSUserDefaults Seemingly not Creating Globally Accessible Variables

I'm new to Swift and iOS in general, and would appreciate any help on this...I'm making an app with one file called ViewController.swift, which contains the ViewController class, and another file called BTService.swift, which contains the BTService class. I have a slider set up in the VC, and I want to take its value and use it in the BTService class. I asked a question about this previously (Swift Reference Variable from Specific Instance of Different Class) and someone suggested I use NSUserDefaults to accomplish this. This is my VC class with the slider value, positionSlider.value assigned to a key sliderValue
class ViewController: UIViewController {
#IBOutlet var positionLabel: UILabel!
#IBOutlet var positionSlider: UISlider!
#IBOutlet var connectionLabel: UILabel!
#IBAction func sliderValChanged(sender: UISlider) {
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
println(positionSlider.value)
defaults.setFloat(Float(positionSlider.value), forKey: "sliderValue") // Write to NSUserDefaults
defaults.synchronize()
let currentValue: Float = defaults.floatForKey("sliderValue")
var currentValueString=NSString(format: "%.5f", currentValue)
sliderValue is stored as a float in NSUserDefaults. Now, from my understanding, I can then go to my BTService class and simply do this:
#IBAction func sliderValChanged(sender: UISlider) {
let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
let currentValue: Float = defaults.floatForKey("sliderValue")
println(currentValue)
}
However, this isn't working. I don't get any syntax errors, but I also don't see any value printed to the console when I tweak the slider. Interesting note is that I do see an output of the value when I put a println statement in the VC, which shows that currentValue is being defined and is functioning like it should. Any help on this would be very much appreciated. Thanks so much!
#IBAction func sliderValChanged(sender: UISlider) {
NSUserDefaults.standardUserDefaults().setFloat(sender.value, forKey: "sliderValue")
let currentValue = NSUserDefaults.standardUserDefaults().floatForKey("sliderValue")
println(currentValue)
}

Resources