I only want the alert to show up if the variable "genderDefault" has not been assigned yet.
This code is suppose to save the choice of the user:
func genderAlert()
{
let alertController = UIAlertController(title: "Quick Question", message: "What's your gender?", preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "Male", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("Male Pressed")
self.genderDefault.setValue("male", forKey: "gender")
}
let cancelAction = UIAlertAction(title: "Female", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("Female Pressed")
self.genderDefault.setValue("female", forKey: "gender")
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
This is the if-statement that controls whether the alert shows up:
if(genderDefault != "male" || genderDefault != "female")
{
genderAlert()
}
Swift 3
let genderDefault = UserDefaults.standard
genderDefault.set(value: AnyObject?, forKey: String) // SET
genderDefault.object(forKey: String) // GET
Swift 2
let genderDefault = NSUserDefaults.standardUserDefaults()
genderDefault.setObject("female", forKey: "gender") // SET
if let gender = genderDefault.stringForKey("gender"){ // GET
if((gender as! String) != "male" || (gender as! String) != "female")
{
genderAlert()
}
}
What ever you do you have to set userDefaults.synchronize() at last so that userDefaults should come to know that now it has to save
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setValue("female", forKey: "gender")
userDefaults.synchronize() // don't forget this!!!!
Related
I am trying to create an app that requires the user to successfully enter a pin before being allowed onto the rest of the app.
I did some searching around and found a basic existing coredata example app that works here.
I went into the xcdatamodel and deleted their attributes and replaced with "pin" which is a String. Here is a screenshot of the xcdatamodel.
Then I modified the ViewController so that the createData UIbutton opens a alertController that prompts the user to enter a new pin twice, checks they are the same, and if they are it creates a coredata entry with that pin.
Here is the relevant code of the ViewController:
import UIKit
import CoreData
class ViewController: UIViewController {
var firstPinNumber:String = ""
var secondPinNumber:String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func createData(_ sender: Any) {
let enterPinAlertController = UIAlertController(title: "Enter New PIN", message: "", preferredStyle: .alert)
enterPinAlertController.addTextField{ (textField1:UITextField)->Void in
textField1.placeholder = "Enter PIN"
textField1.isSecureTextEntry = true
}
enterPinAlertController.addTextField{ (textField2:UITextField)->Void in
textField2.placeholder = "Re-Enter PIN"
textField2.isSecureTextEntry = true
}
let okAction = UIAlertAction(title: "OK", style: .cancel) {(action) in
if let textFields = enterPinAlertController.textFields {
let theTextFields = textFields as [UITextField]
self.firstPinNumber = theTextFields[0].text!
self.secondPinNumber = theTextFields[1].text!
if self.firstPinNumber != self.secondPinNumber {
print ("PINs dont match!")
let pinsDontMatchAlertController = UIAlertController(title: "PINs don't match!", message: "Try again", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .cancel) {(action) in
}
pinsDontMatchAlertController.addAction(okAction)
self.present(pinsDontMatchAlertController, animated: true, completion: nil)
}
}
}
enterPinAlertController.addAction(okAction)
self.present(enterPinAlertController, animated: true, completion: nil)
createPIN(pinNum: secondPinNumber)
}
func createPIN(pinNum: String){
//As we know that container is set up in the AppDelegates so we need to refer that container.
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
//We need to create a context from this container
let managedContext = appDelegate.persistentContainer.viewContext
//Now let’s create an entity and new user records.
let userEntity = NSEntityDescription.entity(forEntityName: "User", in: managedContext)!
let user = NSManagedObject(entity: userEntity, insertInto: managedContext)
user.setValue(pinNum, forKeyPath: "pin")
print(user.value(forKey: "pin") as Any)
//Now we have set the pin. The next step is to save it inside the Core Data
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
#IBAction func retrieveData(_ sender: Any) {
let storedPin = retrievePIN()
print(storedPin)
}
func retrievePIN()->String {
var storedPin:String = ""
//As we know that container is set up in the AppDelegates so we need to refer that container.
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return "" }
//We need to create a context from this container
let managedContext = appDelegate.persistentContainer.viewContext
//Prepare the request of type NSFetchRequest for the entity
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
fetchRequest.fetchLimit = 1
// fetchRequest.predicate = NSPredicate(format: "username = %#", "Ankur")
// fetchRequest.sortDescriptors = [NSSortDescriptor.init(key: "email", ascending: false)]
//
do {
let result = try managedContext.fetch(fetchRequest)
for data in result as! [NSManagedObject] {
if data.value(forKey: "pin") != nil {
storedPin = data.value(forKey: "pin") as! String
print(storedPin)
} else {
print ("Found nil")
}
}
} catch {
print("Failed")
}
return storedPin
}
Using breakpoints I have ascertained that it enters the createPin() function, but it seems to enter that function BEFORE it presents the enterPinAlertController to enter the new pin, even though createPin() is called AFTER the enterPinAlertController is presented.
Also if I use the retrieveData UIButton it prints out "Found nil"
So if what I'm thinking is correct, its creating a coredata entry with an empty string, or nothing at all?
How can I fix this so that it creates a coredata entry with the string the user enters as the new pin, and also retrieves it later?
Your call to createPin needs to be inside the action handler for okAction. As you have it now, secondPinNumber will be called before the alert has been shown, so it will be empty or nil, depending on how you initialise it.
IBAction func createData(_ sender: Any) {
let enterPinAlertController = UIAlertController(title: "Enter New PIN", message: "", preferredStyle: .alert)
enterPinAlertController.addTextField{ (textField1:UITextField)->Void in
textField1.placeholder = "Enter PIN"
textField1.isSecureTextEntry = true
}
enterPinAlertController.addTextField{ (textField2:UITextField)->Void in
textField2.placeholder = "Re-Enter PIN"
textField2.isSecureTextEntry = true
}
let okAction = UIAlertAction(title: "OK", style: .cancel) {(action) in
if let textFields = enterPinAlertController.textFields,
let firstPinNumber = textFields[0].text,
let secondPinNumber = textFields[1].text,
firstPinNumber == secondPinNumber {
createPIN(pinNum: secondPinNumber)
} else {
print ("PINs dont match!")
let pinsDontMatchAlertController = UIAlertController(title: "PINs don't match!", message: "Try again", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .cancel)
pinsDontMatchAlertController.addAction(okAction)
self.present(pinsDontMatchAlertController, animated: true, completion: nil)
}
}
}
enterPinAlertController.addAction(okAction)
self.present(enterPinAlertController, animated: true, completion: nil)
}
I want to save the button enable and disable value in userdefault. I wrote the following code but nothing happened. Please tell me how to save and fetch button enable and disable value.
I want, when the ibaction button is pressed, it should disable and when closes the app and reopen the app then it should save the disable state of button.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var btn2: UIButton!
#IBOutlet weak var btn1: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// let def = UserDefaults.standard.bool(forKey: "val")
// btn1.isEnabled = def
}
override func viewWillAppear(_ animated: Bool) {
let def = UserDefaults.standard.bool(forKey: "val")
print(def)
//btn1.isEnabled = def
}
#IBAction func btn1Pressed(_ sender: UIButton) {
let def = UserDefaults.standard.bool(forKey: "val")
print("Button one pressed")
let otherAlert = UIAlertController(title: "Button 1!!", message: "Here is button one.", preferredStyle: UIAlertControllerStyle.alert)
let okaction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (UIAlertAction) in
print("OK pressed")
self.btn1.isEnabled = false
UserDefaults.standard.set(self.btn1.isEnabled, forKey: "val")
}
let dismiss = UIAlertAction(title: "No", style: UIAlertActionStyle.cancel) { (UIAlertAction) in
self.btn1.isEnabled = true
UserDefaults.standard.set(self.btn1.isEnabled, forKey: "val")
print("No pressed")
}
otherAlert.addAction(dismiss)
otherAlert.addAction(okaction)
present(otherAlert, animated: true, completion: nil)
let def1 = UserDefaults.standard.bool(forKey: "val")
btn1.isEnabled = def1
}
#IBAction func btn2Pressed(_ sender: UIButton) {
print("Button Two pressed")
}
}
Instead of saving self.btn1.isEnabled save the value you are applying to that. Can't you do this directly ?
override func viewDidLoad() {
super.viewDidLoad()
// You need to check if key is present or else you will get false as default value and your button will disabled only
if isKeyPresentInUserDefaults(key: "val") {
let def = UserDefaults.standard.bool(forKey: "val")
btn1.isEnabled = def
}
}
// Check key is present or not
func isKeyPresentInUserDefaults(key: String) -> Bool {
return UserDefaults.standard.object(forKey: key) != nil
}
#IBAction func btn1Pressed(_ sender: UIButton) {
let defaults = UserDefaults.standard
defaults.set(false, forKey: "val")
print("Button one pressed")
let otherAlert = UIAlertController(title: "Button 1!!", message: "Here is button one.", preferredStyle: UIAlertControllerStyle.alert)
let okaction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (UIAlertAction) in
print("OK pressed")
self.btn1.isEnabled = false
defaults.set(false, forKey: "val")
}
let dismiss = UIAlertAction(title: "No", style: UIAlertActionStyle.cancel) { (UIAlertAction) in
self.btn1.isEnabled = true
defaults.set(true, forKey: "val")
print("No pressed")
}
otherAlert.addAction(dismiss)
otherAlert.addAction(okaction)
present(otherAlert, animated: true, completion: nil)
// No need of these 2 lines
let def1 = defaults.bool(forKey: "val")
btn1.isEnabled = def1
}
I am trying to recovery a value from firebase database and compare it with a UITextField value, in case of matching, I save it to a var that I will us. The problem is that the variable in question has a default value just when I use it.
Above I show my func code where the variable affected is "codeRecovered":
#IBAction func signUpAction(_ sender: AnyObject)
{
var codeRecovered: String = ""
if emailSignUpTextField.text == "" || self.secretCodeTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email, pin code and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else {
self.dbHandler = self.ref?.child("Companies").observe(.value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value as! [String:String]
if let auxSecretCode = value["secretCode"]
{
if auxSecretCode == self.secretCodeTextField.text{
print("Value recovered OK(works fine): \(auxSecretCode)")
codeRecovered = auxSecretCode
print("Recovered value saved OK(works fine): \(codeRecovered)")
}
}
}
})
//Here codeRecovered is already ""
print("\(codeRecovered) is the recovered value(empty) and \(self.secretCodeTextField.text ?? "def") is the textField value")
if codeRecovered != self.secretCodeTextField.text{
let alertController = UIAlertController(title: "Error", message: "Please enter a correct pin code", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
//....
Async calls with sync result use....
#IBAction func signUpAction(_ sender: AnyObject)
{
var codeRecovered: String = ""
if emailSignUpTextField.text == "" || self.secretCodeTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email, pin code and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
} else {
self.dbHandler = self.ref?.child("Companies").observe(.value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value as! [String:String]
if let auxSecretCode = value["secretCode"]
{
if auxSecretCode == self.secretCodeTextField.text{
print("Value recovered OK(works fine): \(auxSecretCode)")
codeRecovered = auxSecretCode
print("Recovered value saved OK(works fine): \(codeRecovered)")
}
}
}
//Here codeRecovered is already ""
print("\(codeRecovered) is the recovered value(empty) and \(self.secretCodeTextField.text ?? "def") is the textField value")
if codeRecovered != self.secretCodeTextField.text{
let alertController = UIAlertController(title: "Error", message: "Please enter a correct pin code", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
})
to use your codeRecovered in a sequence it must be within self.dbHandler = self.ref?.child("Companies").... block because it runs in async thread
I am working on a college project and I was having this problem that I don't know how to fix. When the user clicks on the Register button his information will be saved but if he didn't fill in the blanks he will get an error message. But the problem is that it will save an empty textfield in the CoreData. So I want to "Catch" that and give them an error without saving an empty textfield to the CoreData.
import UIKit
import CoreData
class ViewRegister: UIViewController {
#IBOutlet weak var txtName: UITextField!
#IBOutlet weak var txtUsername: UITextField!
#IBOutlet weak var txtPassword: UITextField!
#IBOutlet weak var txtPhone: UITextField!
#IBOutlet weak var txtAddress: UITextField!
#IBOutlet weak var txtCity: UITextField!
#IBAction func btnRegister(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newContact = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
newContact.setValue(txtName.text, forKey: "name")
newContact.setValue(txtUsername.text, forKey: "username")
newContact.setValue(txtPassword.text, forKey: "password")
newContact.setValue(txtPhone.text , forKey: "phone")
newContact.setValue(txtAddress.text , forKey: "address")
newContact.setValue(txtCity.text , forKey: "city")
do{
try context.save()
print ("Saved")
}
catch{
print ("Error")
}
if txtCity.text == "" || txtAddress.text == "" || txtPhone.text == "" || txtPassword.text == "" || txtUsername.text == "" || txtName.text == ""
{
// Create the alert controller
let alert = UIAlertController(title: "Ops!!", message: "Please fill in the information", preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alert.addAction(okAction)
alert.addAction(cancelAction)
// Present the controller
self.present(alert, animated: true, completion: nil)
}
else
{
txtName.text = ""
txtUsername.text = ""
txtPassword.text = ""
txtPhone.text = ""
txtAddress.text = ""
txtCity.text = ""
// Create the alert controller
let alert = UIAlertController(title: "Successfully Registered!", message: "Thank you for registering in our application", preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alert.addAction(okAction)
alert.addAction(cancelAction)
// Present the controller
self.present(alert, animated: true, completion: nil)
}
}
}
I only can repeat the comment by #Lepidopteron: Why don't you call your contact initialization and save-call in your "else" code part?
Like this?
#IBAction func btnRegister(_ sender: Any) {
if txtCity.text == "" || txtAddress.text == "" || txtPhone.text == "" || txtPassword.text == "" || txtUsername.text == "" || txtName.text == ""
{
// Create the alert controller
let alert = UIAlertController(title: "Ops!!", message: "Please fill in the information", preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alert.addAction(okAction)
alert.addAction(cancelAction)
// Present the controller
self.present(alert, animated: true, completion: nil)
}
else
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newContact = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
newContact.setValue(txtName.text, forKey: "name")
newContact.setValue(txtUsername.text, forKey: "username")
newContact.setValue(txtPassword.text, forKey: "password")
newContact.setValue(txtPhone.text , forKey: "phone")
newContact.setValue(txtAddress.text , forKey: "address")
newContact.setValue(txtCity.text , forKey: "city")
do{
try context.save()
print ("Saved")
}
catch{
print ("Error")
}
txtName.text = ""
txtUsername.text = ""
txtPassword.text = ""
txtPhone.text = ""
txtAddress.text = ""
txtCity.text = ""
// Create the alert controller
let alert = UIAlertController(title: "Successfully Registered!", message: "Thank you for registering in our application", preferredStyle: .alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alert.addAction(okAction)
alert.addAction(cancelAction)
// Present the controller
self.present(alert, animated: true, completion: nil)
}
}
Im trying to build a todo list with coreData, my goal is to have an error pop-up notification if a user tries to just click the "add" button without entering any text in the text-field.
I currently have the pop-up notification working but once i dismiss the notification and then add text into the text-field and click the "add" button the application crashes.
#IBAction func addBtnTaskPressed(_ sender: Any) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Task(context: context)
//have to add an if let here.
if let text = textField.text, !text.isEmpty{
task.name = textField.text
//save data to coredata
(UIApplication.shared.delegate as! AppDelegate).saveContext()
} else {
let alert = UIAlertController(title: "Error:", message: "Cannot Add Empty Task", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
I think you are not saving coreData properly. Try this (I haven't tested it though)
#IBAction func addBtnTaskPressed(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: "Task", in: context)
let task = NSManagedObject(entity: entity!, insertInto: context) as! Task
//have to add an if let here.
if let text = textField.text, !text.isEmpty{
task.name = textField.text
//save data to coredata
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
} else {
let alert = UIAlertController(title: "Error:", message: "Cannot Add Empty Task", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}