Initialize object in parse - ios

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:

Related

Update only one of two UITextFields stored in userData in Swift 5.3

Using UserDefaults to store two user input fields to be used throughout various VCs. UILabels show the current settings, while UITextFields accept updated input. I can set, store, display and update the two fields, but updates have to be in tandem. I cannot figure out the proper method to update only one of the two fields. As an example, update the email only, without touching "evernote" in my case. Without the work around below, and when only inputting one of two fields, the second non-input field is overridden as blank.
As a work around, I include the saved data as the initial input for the two UITextFields. Code works, just does not seem to be optimal. Ideally the two UITextFields would not have initial values. I have mucked around with != null statements in the button function, but to no avail.
Any advice would be greatly appreciated, and thank you in advance.
Class to share userData input among VCs:
class UDM {
static let shared = UDM()
let userData = UserDefaults(suiteName: "xxxx.saved.data")!
}
Outlets and Actions:
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var evernoteLabel: UILabel!
#IBOutlet weak var enterEmail: UITextField?
#IBOutlet weak var enterEvernote: UITextField?
#IBAction func saveButton(_ sender: UIButton) {
UDM.shared.userData.set(enterEmail?.text, forKey: "email")
UDM.shared.userData.set(enterEvernote?.text, forKey: "evernote")
}
viewDidLoad UI:
let emailObject = UDM.shared.userData.object(forKey: "email")
if let email = emailObject as? String {
enterEmail?.text = email
emailLabel.text = email
}
let evernoteObject = UDM.shared.userData.object(forKey: "evernote")
if let evernote = evernoteObject as? String {
enterEvernote?.text = evernote
evernoteLabel.text = evernote
}
Posting in case someone else is as dumb as I am. In the if/then statements for the UITextFields, I looked at enterEmail or enterEvernote as fields. Once I realized you need to look at the .text in the fields, it all fell into place. Updated action is pretty simple then:
#IBAction func saveButton(_ sender: UIButton) {
if enterEmail?.text != "" {
UDM.shared.userData.set(enterEmail?.text, forKey: "email")
}
if enterEvernote?.text != "" {
UDM.shared.userData.set(enterEvernote?.text, forKey: "evernote")
}
}

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
}

Swift get value data from protocol

i need help with my code for swift 5,
so i make a struct and protocol to store list from uitextfield and now i wanna show that data in a UiTextView in another view controller
struct PatientNote {
var note : String
init(note :String) {
self.note = note
}
}
protocol AddNotesDelegate {
func AddNotes(controller : UIViewController, notes: PatientNote)
}
class AddNotesController: UIViewController {
var delegate : AddNotesDelegate!
#IBOutlet weak var Notes: UITextView!
#IBAction func addNotes(_ sender: Any) {
if let notes = self.Notes.text {
let patientNote = PatientNote(note: notes)
self.delegate.AddNotes(controller: self, notes: patientNote)
print(patientNote.note)
}
}
}
and now i wanna show in my view controller but i get this error of "Cannot convert value of type 'PatientNote' to expected argument type 'String'" in this viewController
class NotePatientController: UIViewController, AddNotesDelegate{
func AddNotes(controller: UIViewController, notes: PatientNote) {
let NotesPatient = PatientNote(note: notes) *this is where i get the error
}
var delegate : AddNotesDelegate!
var pasien : PatientNote!
override func viewDidLoad() {
super.viewDidLoad()
PatientTextView.text = pasien.note
}
#IBOutlet weak var PatientTextView: UITextView!
//in this ibaction i edit the notes that i get from the first Vc which is AddNotesController
#IBAction func Save(_ sender: UIButton) {
if let notes = self.PatientTextView.text {
let pasienNotes = PatientNote(note: notes)
self.delegate.AddNotes(controller: self, notes: pasienNotes)
}
}
}
i try to show the note from the AddNotesController to the NotePatientController, and in the NotePatientController i can edit and save the notes in UiTextView.
so i know i must be using the protocol in a wrong way, can someone help me how should i use it? im still kinda new in swift so could probably use any help i can get, Cheer!
Change let notesPatient = PatientNote(note: notes) to let notesPatient = PatientNote(note: notes.note)
It appears PatientNote takes a String as an argument but you passed an already created PatientNote to it instead. The below syntax, using notes.note would be a cleaner solution without involving initialising a new PatientNote.
func AddNotes(controller: UIViewController, notes: PatientNote) {
print(notes.note) // access the note String like this
}

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.

Is there a way for the text in a label to automatically update the display

I'm trying to make an app that lets users input 4 numbers and display what cellular network is that number. Is there a way to automatically display the numbers in the label after the user inputs the numbers without clicking a button? I actually have a code that lets the user input the number but the user must click the enter button for it to display the result on the label. Is there a way for it to automatically display the result? By the way, I'm actually new to swift so I apologize. Here is the code:
import UIKit
import Firebase
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
#IBOutlet weak var numField: UITextField!
#IBOutlet weak var answerField: UILabel!
#IBAction func enterButton(sender: AnyObject) {
matchNumber()
}
func matchNumber(){
let number: String = numField.text!
let numRef = Firebase(url: "https://npi2.firebaseio.com/num_details")
numRef.queryOrderedByKey().observeEventType(.ChildAdded, withBlock: { snapshot in
let network = snapshot.value as! String!
if snapshot.key == self.numField.text! {
self.answerField.text = network
}
else {
self.answerField.text = "Missing"
}
})
}
Add a target to your numField, something like this...
override func viewDidLoad() {
super.viewDidLoad()
self.numField.addTarget(self, action: "editingChanged:", forControlEvents: .EditingChanged)
}
This will trigger the editingChanged method every time a character changes in the numField.
func editingChanged(textField:UITextField) {
if let text = textField.text {
if text.characters.count == 4 {
matchNumber()
}
}
}
Finally we check if there is a string in the input and if it is 4 characters long before running the matchNumber method.
You could use the didSet method.
var numberstring = String() {
didSet {
yourlabel.text = numberstring
}
}
If you are using textfield to take input then you can use textfieldDidEndEditing delegate method.

Resources