uitextfield in swift 3 not saving - ios

My textfield is not saving. My code is listed below. Thanks
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet weak var textext: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func savesavesave(_ sender: Any) {
let myText = textext.text
UserDefaults.standard.set(myText, forKey: "myKey")
}

Ensure your textfield is not being first responder. For example, you may call the below code before saving:
#IBAction func savesavesave(_ sender: Any) {
textext.resignFirstResponder()
let myText = textext.text
UserDefaults.standard.set(myText, forKey: "myKey")
}

You should try this for saving textfield into UserDefaults:
let myText = TextFiled1.text
UserDefaults.standard.set(myText, forKey: "myKey")
If you want to get that textfield value then write this:
let value = UserDefaults.standard.string(forKey: "myKey")
print(value!)

Synchronize the user defaults with its method and test if working
I'm writing from my memory:
UserDefaults.standard.set(myText, forKey: "myKey")
UserDefaults.standard.synchronize()
EDIT
from apple documentation
// Note that we don't synchronize with the file system or anything; this will happen
when the app quits. There are times when an explicit synchronize might be necessary,
but often it's not. Synchronizing unecessarily can also be a performance issue.
According apple docs I understands (you may think otherwise) that if you want to get the value during runtime, and not saving it in your variable - you should sync manually
EDIT AGAIN
Thanks to #LeoDabus I understand that maybe it's available during runtime too. So don't count my answer

Yes, it is not necessary synchronize happens, if app is about to exit. For accessing the information during app launches it is necessary that the synchronization happens. For more info you can check: iOS NSUserDefaults access before synchronize completion

Related

How can I load all the data stored in the array, when the app starts again (Swift)?

I have to implement a function that loads the stored data into the shopping list array, when the app starts, and a function that stores the current contents of my list when the button is pressed. I used UserDefaults class and it works for the second function (when the button is pressed) but not for the first one (when the app starts). If I restart the app and press the button, I see that only the last input was stored. How can I fix the code if I want to store all data from the array?
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var inputEntered: UITextField!
// keyboard gives up the first responder status and goes away if return is pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
inputEntered.resignFirstResponder()
return true
}
var shoppingList: [String] = []
#IBAction func buttonAddToList(_ sender: UIButton) {
if let item = inputEntered.text, item.isEmpty == false { // need to make sure we have something here
shoppingList.append(item) // store it in our data holder
}
inputEntered.text = nil // clean the textfield input
print(shoppingList.last!) // print the last element to avoid duplicates on the console
storeData()
}
// this function stores the current contents of my list when the button is pressed
func storeData () {
let defaults = UserDefaults.standard
defaults.set(inputEntered.text, forKey: "Saved array")
print(defaults)
}
// to call the function storeDate(), when the app restarts
override func viewDidLoad() {
super.viewDidLoad()
inputEntered.delegate = self
// Do any additional setup after loading the view.
storeData()
}
}
You can add a getter and a setter to your array and persist your values to user defaults. This way you don't need to call storeData and or remembering to load the data when initialising your array:
var shoppingList: [String] {
get {
UserDefaults.standard.stringArray(forKey: "shoppingList") ?? []
}
set {
UserDefaults.standard.set(newValue, forKey: "shoppingList")
}
}
You are calling storeData() in viewDidLoad, but inputEntered is empty then, so you are storing blank data.
Also, defaults.set(inputEntered.text, forKey: "Saved array") doesn't append new data onto the key -- it overwrites what is there. So you are not storing the array, you are only storing the last value.
You need to store shoppingList to store the array.
I'm unsure if I have got what you are asking for but have you tried looking into UITextFieldDelegate.
If you add this, it will ensure add the protocols of which I am sure there is a method that can be called when the user finishes editing text field.

How do I share data between iOS app and today view extension

I'm trying to show the persons name in the today view extension; but I can't seem to do this. I've watched so many YouTube video's but they never helped. So if you can, I want you to answer this.
How the app works: You type your name inside the app. And the it will show in the today view extension.
About the app: I have a text field and button. The textfield is the persons name and the button is the save the name.
I want to show the name in the today extension.
Thank you.
Add the group to the entitlements/capabilities.
Go to the capabilities tab of the app's target
Enable App Groups
Create a new app group, entitled something appropriate. It must start with group..
Let Xcode go through the process of creating this group for you.
Save data to NSUserDefaults with group ID and use it in your extension.
From Apple's App Extension Guide :
https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
In the main app, save person name:
let defaults = UserDefaults(suiteName: "your group ID")
defaults!.set("person name", forKey: "key for person name")
defaults!.synchronize()
In the extension, you can use saved person name:
let defaults = UserDefaults(suiteName: "your group ID")
let savedPersonName = defaults!.string(forKey: "key for person name")
Just a quick notice as I too have missed it
In order to get it working create the group on app target
and then on Today's target add Group Capability as well and tick the one just created from the main app's target (it should be listed)
here is a simple example of today extension in this example, I am only showing and updating the user name
this my today extension storyboard image
and today-view-Controller code is:
import UIKit
import NotificationCenter
class TodayViewController: UIViewController, NCWidgetProviding {
#IBOutlet weak var lnameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
if let name = UserDefaults.init(suiteName: "group.com.ahmad.widget")?.value(forKey: "name"){
lnameLabel.text = name as? String
}
else{
lnameLabel.text = "Wait..."
}
}
func widgetPerformUpdate(completionHandler: (#escaping (NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
completionHandler(NCUpdateResult.newData)
}
}
I create a storyboard and add a button in this than on his button action I update the user name on today extension
code of viewController is :
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var nameTextfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func SetNameOnWigetAction(_ sender: Any) {
nameLabel.text = nameTextfield.text
UserDefaults.init(suiteName: "group.com.ahmad.widget")?.setValue(nameTextfield.text, forKey: "name")
}
}

Accessing UserDefaults in Swift from other viewControllers

In my application, I use UserDefaults to store the user's login status (whether they are logged in or not), and their username. It works fine in that when I login, close the app, and open it again my app skips the login page and recognizes that I am already logged in. Although, I am now trying to install a logout button to a separate viewController. When clicked, this logout button needs to 1.) Reset UserDefaults.loginStatus to "False" 2.) Reset UserDefaults.username to nil 3.) Perform a segue to the login page.
Here is the related code from my ViewController.swift file. This is the first viewController which controls the loginPage.
import UIKit
import Firebase
let defaults = UserDefaults.standard
class ViewController: UIViewController {
func DoLogin(username: String, password: String) {
//I Am not including a lot of the other stuff that takes place in this function, only the part that involves the defaults global variable
defaults.setValue(username, forKey: "username")
defaults.setValue("true", forKey: "loginStatus")
defaults.synchronize()
self.performSegue(withIdentifier: "loginToMain", sender: self) //This takes them to the main page of the app
}
override func viewDidLoad() {
super.viewDidLoad()
if let stringOne = defaults.string(forKey: "loginStatus") {
if stringOne == "true" { //If the user is logged in, proceed to main screen
DispatchQueue.main.async
{
self.performSegue(withIdentifier: "loginToMain", sender: self)
}
}
}
}
Below is my code in SecondViewController.swift, particularly the logout function.
import UIKit
import Firebase
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let username = defaults.string(forKey: "username") {
checkAppSetup(username: username) //This is an unrelated function
//I included this because this works fine. Proving that I am able to read the defaults variable fine from this other viewController
}
}
#IBAction func logout(_ sender: Any) {
defaults.setValue("false", forKey: "username")
defaults.setValue("false", forKey: "loginStatus")
defaults.synchronize()
performSegue(withIdentifier: "logoutSegue", sender: nil)
}
When the logout function is run, the segue performs fine but the default values do not change. Can someone explain why and what I can do to get around this?
**Side note, I am not actually going to set the defaults to "false" and "false". That is just temporary for while I am debugging this issue.
Several things.
You should be using set(_:forKey:) and object(_:forKey) to read and write key/value pairs to defaults, not setValue(_:forKey). (Your use of defaults.string(forKey: "loginStatus") is correct, however.)
You should probably be writing a nil to the userName key:
defaults.set(nil, forKey: "username")
And your logout IBAction should almost certainly be setting loginStatus to false, not true.
Try changing those things.
Also, there is no reason to call synchronize unless you are terminating your app in Xcode rather than pressing the home button on the device/simulator in order to let it exit normally.
Hey i used the exactly same concept recently :
1) In your initial view, in the viewDidLoad() , check whether somebody is already logged in or not, and only one user can be logged in one device at a time, so we check like
let defaults = UserDefaults.standard
if defaults.object(forKey: "userName") != nil && defaults.object(forKey: "userPassword") != nil
{
let loginObject = self.storyboard?.instantiateViewController(withIdentifier: "YourSecondViewController") as! YourSecondViewController
//As someone's details are already saved so we auto-login and move to second view
}}
2) In your sign in button function , check whatever condition you want to check and then, inside the same, if condition satisfies then save data to userDefaults.
// If no details are saved in defaults, then control will come to this part, where we will save the entered userName and Password
let defaults = UserDefaults.standard
defaults.set(self.enteredUseName, forKey: "userName")
defaults.set(self.enteredPassword, forKey: "Password")
defaults.synchronize()
3) On logout button , delete the userDefaults and load the login view again :
let defaults = UserDefaults.standard
defaults.removeObject(forKey: "userName") //We Will delete the userDefaults
defaults.removeObject(forKey: "userPassword")
defaults.synchronize() //Sync. the defaults.
navigationController?.popToRootViewController(animated: true) //Move Back to initial view.
4) If you are using a navigation control, that you must be using :P then you will surely see the back button which will open the second view if clicked, for that you can hide the navigation bar in viewDidLoad() of your login view
self.navigationController?.navigationBar.isHidden = true

Saving text in UITextView Swift 3

I am creating a To-Do App on IOS Platform Swift 3
I am trying to save note in UITextView so when i hit back or terminate application the data is saved.
StoryBoard Have a UITextView and a save button at the navigation bar
How to make user enter his text in UITextView and save it
class Details: UIViewController, UITextViewDelegate{
// MARK: - IB
#IBOutlet weak var noteText: UITextView!
#IBAction func addNote(_ sender: UIButton) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let addNote = Note(context: context)
addNote.details = noteText.text!
//Saving
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var Notes: [Note] = []
func getData() {
do {
Notes = try context.fetch(Note.fetchRequest())
} catch {
print("Fetching Failed")
}
}
override func viewWillAppear(_ animated: Bool) {
getData()
}
override func viewDidLoad() {
super.viewDidLoad()
let MyIcon = UIImageView(image: UIImage(named: "037_Pen"))
self.navigationItem.titleView = MyIcon
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Any idea how to display it ?
Created Entity called Note with Attribute details of type String
Dealing with data in iOS application
If you want to save your data inside application then you need to do something more inside your application for data saving purpose. This way you can save data inside application weather terminate application it will show your saved data and fetch again.
1.) For Short Date save can use UserDefaults
2.) By using SQLite
3.) By Using Coredata
4.) By Using Realm, For more details check Example.
You need to create database to save the text value every time as per your requirement.
You can create the database by using any one of the below :
Core dataGet tutorial from here
SQLite Get tutorial from here
Save your text data by using anyone these and then fetch the data and assign at the UI.

Pass data between ViewController and TableVC with NSUserDefaults (Swift)

How to pass the state of a NSUserDefault between several Classes in Swift?
In this case I want to pass this state between one TableViewController, where you change the state on the switch, and one initial VC.
Here is a little model to understand...
I used this to set the state with the switch:
#IBAction func changeTouchIDState(sender: AnyObject) {
if TouchIDSwitch.on {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "State")
} else {
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "State")
}
}
If the state = true, the initial VC should ask about the Authentication.
Thanks!
Your question need little more explanation, I don't understand why you want to pass the value as you are already storing in NSUserDefaults which you can access in any class of your app.
As per my understanding to your problem I'm suggesting the solution:
As you already storing State in NSUserDefaults so before presenting initial VC check NSUserDefaults.standardUserDefaults().boolForKey("State") if its true, ask authentication otherwise don't.
After setting the bool, you should synchronise:
NSUserDefaults.standardUserDefaults().synchronize()
Then, you can access that value with:
func boolForKey(_ defaultName: String) -> Bool

Resources