Adding multiple textfield to firebase using swift - ios

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(...)

Related

Swift Core Data - Save, Populate, Edit an Entity Attribute/Relationship

I'm pretty new to iOS dev/Core Data and am having trouble implementing one part of my workflow within my app. See below:
Core Data Properties:
item
Attributes: title, amount, date, status, category (rel), note (rel)
note
Attributes: title, contents, createdAt, updatedAt, item (rel)
When a user creates a new item, all attributes are required, except for .note as I'd like to give the user the option to create a note at a later time if only needed.
What I want to accomplish:
User selects row to display item details
On item details view, user selects notes (highlighted in yellow above) to go to Add/Edit notes
The note is just a single object that the user can enter/update the note. So basically, one note per item.
MY CODE
Xcode 11.5, Swift 5
import UIKit
import CoreData
class NoteVC: UIViewController, UITextFieldDelegate, UITextViewDelegate {
//MARK: - Core Data
var item: Item?
var context: NSManagedObjectContext!
//MARK: - Outlets
#IBOutlet weak var headerContainer: UIView!
#IBOutlet weak var headerTitle: UILabel!
#IBOutlet weak var noteView: UIView!
#IBOutlet weak var noteTitleTextField: UITextField!
#IBOutlet weak var noteContentTextView: UITextView!
#IBOutlet weak var noteDataLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
override func viewWillDisappear(_ animated: Bool) {
super .viewWillDisappear(animated)
//Update note
if let title = noteTitleTextField.text, !title.isEmpty {
item?.notes?.title = title
item?.notes?.contents = noteContentTextView.text
}
item?.notes?.updatedAt = Date()
item?.notes?.contents = noteContentTextView.text
}
private func setupView() {
noteTitleTextField.text = item?.notes?.title
noteContentTextView.text = item?.notes?.contents
noteDataLabel.text = DateHelper.convertDate(date: Date())
}
//MARK: - Actions
#IBAction func doneButtonTapped(_ sender: UIButton) {
item?.notes?.title = noteTitleTextField.text
item?.notes?.contents = noteContentTextView.text
item?.notes?.createdAt = Date()
dismiss(animated: true)
}
}
MY PROBLEM
I'm having an issue creating the new note and assign it to that item and therefore populating the note details for editing. I was able to set the attributes for item.date, .category successfully to another modal view controller (so the passing of data is working), but to no avail with the Notes. Not sure if its because of the relationship or not. Again, I'm a n00b to Core Data so please forgive me for sounding simple.
Any help is appreciated.
Asking for a friend, =P
adrapp
Your problem seems to be that you are not creating a Note entity before trying to assign its properties.
The correct pattern to create a note and associate it with your item would be something like this:
if let note = NSEntityDescription.insertNewObject(forEntityName: "note", into: context) as? Note {
//set note properties
note.title = noteTitleTextField.text
note.contents = noteContentTextView.text
note.createdAt = Date()
//set relationship to item
item.note = note
}
Please verify the name of the entity ("note") and class ("Note") match what you defined in your project.
To allow updating an existing note, you need to check first if there is an existing note. You could modify the code above as follows:
// get the existing note, if any, or create a new one
let note = item.note ?? NSEntityDescription.insertNewObject(forEntityName: "note", into: context) as? Note
// if note existed or was successfully created...
if let note = note {
//set note properties
note.title = noteTitleTextField.text
note.contents = noteContentTextView.text
if item.note == nil {
note.createdAt = Date()
}
else {
note.updatedAt = Date()
}
//set relationship to item
item.note = note
}

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.

EXC_BAD_INSTRUCTION when textFields are empty

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.

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.

realm io returns empty objects (realm 0.93.2)

I've just update my realm to 0.93.2 from 0.91.1 using cocoapods.
I now get empty objects in my query results. So I made a simple app just to test from scratch but I still get the same results.
Here is my test code (basically just one textfield and two buttons (add and print):
import UIKit
import RealmSwift
class Person: Object {
var name = "Empty Value"
}
class ViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
var realm = Realm()
override func viewDidLoad() {
super.viewDidLoad()
println(realm.path)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addTapped(sender: UIButton) {
var person = Person()
person.name = nameTextField.text
realm.write {
self.realm.add(person)
println("Person added: \(person.name)")
}
}
#IBAction func printListTapped(sender: UIButton) {
println("\n\nPeople\n")
for person in realm.objects(Person) {
println("Person: \(person.name)")
}
}
}
The data is saved to the database, as they're seen in the Realm Browser.
But the objects returned by realm.objects(Person) are all empty.
This is the output of the "printListTapped" function after adding 2 items:
People
Person: Empty Value<br/>
Person: Empty Value
I'm really not sure what I'm missing here. Thanks in advance.
The issue here is that your name property is declared without dynamic, so it's completely invisible to Realm. It should work if you declare it as dynamic var name = "Empty Value" instead.

Resources