I have three ViewController two of them have images and TextFields to input from user, and the third one is to display the first and second data and save it .
How can I temporarily save data entered from the user and when the user finishes all the required steps, a summary of the data is called for viewing and then uploaded to the firebase database?
I'm using Swift 4
Define a struct that can hold all of the data the user can enter and that eventually needs to be persisted.
Pass an instance of this struct from view controller to view controller where each controller populates which ever fields it is responsible for.
After the last screen, the struct will contain all of the data. Process it as needed.
The above assumes the user will complete the whole process in one use of your app. If you need to support the ability for the user to start now and finish later (and the app could be killed and restarted in the middle), then this basic idea still works but you need to add code to encode/decode the struct to/from a file. Make your struct Codable and use PropertyListEncoder/Decoder.
all type of Data store in UserDefaults
Like - Float , Double, Int , Bool, URL ...
Description here
UserDefaults.standard.set("Value", forKey: "key")
Get Value
UserDefaults.standard.string(forKey: "key")
Related
im making a project for listening to episodes of a podcast as if they're real cassettes. The idea is that some info about the episode shown on the cassette model + it's audio file are stored in a class, then before putting the cassette in the player, being able to change the class resource the cassette takes from with buttons. My problem is that it doesnt let me change it on runtime, just set it on the ready function.
The way the cassette script loads the data:
onready var data = preload("res://MAGs/Season1/Ep1.tres")
The way im trying to change it:
func _ep_select():
data = load(<different cassette's data>)
If its impossible to change it on runtime, what should i use instead of this?
I created a string value and stored it in a UserDefault on one view controller like so:
letSwimmerOneName = "John"
UserDefaults.standard.set(String(swimmerOneName), forKey: "twoFreelayNameOne
And I'm trying to retrieve that data on a different view controller like so:
var swimmerOneName = UserDefaults.standard.string(forKey: "twoFreelayNameOne")
I'm not getting any errors or crashes, it just simply doesn't work. So I was wondering if UserDefaults transfer across the entire project or stay put in the view controller they are created in.
You are able to retrieve data stored in UserDefaults across different view controllers. My issue was created on where I had placed the UserDefaults and in the way that I declared my variables that were to be assigned this UserDefault value. TLDR: Sloppy formatting.
In my app I use CloudKit and a user's private CKDatabase to store records. I do fetches for changes when the app starts as it adviced at WWDC 2016.
Firstly, I call the fetchDatabaseChanges(database: CKDatabase, databaseTokenKey: String, completion: #escaping () -> Void) method.
Inside this method in changesOperation.fetchDatabaseChangesCompletionBlock I save a CKServerChangeToken to userDefaults for a key : ckDatabaseToken.
I also call the fetchZoneChanges(database: database, databaseTokenKey: databaseTokenKey, zoneIDs: changedZoneIDs, completion in the changesOperation.fetchDatabaseChangesCompletionBlock of the fetchDatabaseChanges method.
In the fetchZoneChanges method there is an operation.recordZoneFetchCompletionBlock. Inside this block we also need to save the value of the token to the UserDefaults. And I'm saving it to another ckZoneToken variable in User Defaults. So inside the fetchZoneChanges I get and save (from/to UserDefaults) the ckZoneToken value, and inside the fetchDatabaseChanges, I get and save (from/to UserDefaults) the ckDatabaseToken value .
Is it the right technique? Or it is better to use only the one variable in both fetchDatabaseChanges and fetchZoneChanges method sto store the value of CKServerChangeToken?
Which will be the best approach?
Swift 3, Xcode 9
I've experimented with both ways and figured out that if we use the one changeToken in user defaults, we get a "Bad sync continuation data" error.
When I've used 2 separate values to store database changes and zone changes, I have had no errors.
So, I think that we have to cache a CKServerChangeToken both in CKDatabase and CKRecordZone separately.
I'm getting the above layout from Parse. What I want is vid 1, 2, and 3 to be in the same row; associated with same object ID. How can I do this? My ultimate goal is to easily retrieve 10 video dictionary's per user on a table view. Will any of this make a difference? I'm saving like this.....
videoDict = ["id":videoId, "title":vidTitleText, "description":vidDescription, "image":vidIMG]
let videoSave = PFObject(className:"UserVideos")
videoSave["user"] = PFUser.currentUser()!.username
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave["vid\(saveValueLBL.text!)"] = videoDict
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Succesfull")
}
}
Where you have let videoSave = PFObject(className:"UserVideos") you are creating a new videoSave object each time. you need to move that outside of your loop so that you're accessing the same object each time instead of making a new one. However, the way you currently have your code set up you'll run into problems, because each object can only have one synchronous action called on it (in this case, your save), so the second, third, maybe even all the way to the 10th save may not occur because it needs the first one to finish before the next one can be called. You need to create your object outside your loop, run the loop, then call the save at the end to make sure it isn't saving until all of the data is updated.
If this isn't all inside of a loop, you need to get the videoSave object back each time, perhaps by storing it onto your user, and then fetching it from the user object.
Put everything outside the loop and keep just the code below inside the loop:
videoDict = ["id":videoId, "title":vidTitleText, "description":vidDescription, "image":vidIMG]
videoSave["vid\(saveValueLBL.text!)"] = videoDict
From what I understand although I saved information in Parse as a Dictionary this is in fact an invalid data type. That's why I'm having trouble retrieving because Parse doesn't recognize the info.
I have in two views that are connected to the menu, in one view I have a text field to enter your e-mail and I want to take that textfield text (that is the email address) to the other view, but I think I need to save that data to the phone so later when the user start the app again he/she will never have to type that address again, and then use that email address in the other view that will send an email to that address. Here is the code that I have:
let configCorreo = ConfigurarCorreo()
let mail = configCorreo.textField.text!
And then I set the recipient using that mail the user typed in the other viewController:
let mc: MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setToRecipients(["\(mail)"])
But I get an error saying: "fatal error: unexpectedly found nil while unwrapping an Optional value"
PrepareForSegue, NSUserDefault and Singleton
You have a few possible options to pass your data to other views depending how you want that data to be handled, I will explain each for you and you can choose which one best fit your need.
prepareForSegue: Method
I recommend this method if you want to hold your data for 1 segue transition, it's a good cause to pass this again to another view afterward you need to create another prepareForSegue within the new view. here is an example on how to do this:
First, you create 2 variables in both views, 1 to send (currentViewController.swift) and 1 to receive (toViewyourGoingController.swift).
currentViewController.swift var dataToSend: AnyObject?
ViewYourGoingController.swift var dataToReceive: AnyObject?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Check your segue, this way you can transfer different data to different view. also make sure the identifier match your segue.
if segue.identifier == "toViewYourGoing" {
//Initial your second view data control
let ExchangeViewData = segue.destinationViewController as! toViewyourGoingController
//Send your data with segue
ExchangeViewData.dataToReceive = dataToSend
}
}
NSUserDefault
Now this method is good if you want to keep your data live as long as the app is installed, once the app is removed this will reset automatically. You also have the option to update the value of the key if you wish, here is how you do NSUserDefault:
I always like to register my NSUserDeafult to default setting, a lot of people just continue with the second step without registering.
Register NSUserDefault in AppDelgate.swift
NSUserDefaults.standardUserDefaults().registerDefaults(["valueName": AnyObject])
Set Value to your NSUserDefault, this depends on what type of data you're storing, should match the one with your registration if you did register. (Example of Boolean data type below)
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "valueName") //Bool Data Type
Available types:
Make sure you synchronize once you set the value to the NSUserDefault, this way it will update instantly, otherwise it will update when it get a chance.
NSUserDefaults.standardUserDefaults().synchronize()
Receive Value: this will receive boolean value since we set boolean and register boolean.
let Variable: Bool! = NSUserDefaults.standardUserDefaults().boolForKey("valueName")
Singleton
Now singleton is basically a global variable that you can use them in any views, but some developers experience some bugs and difficulties, use it at your own risk, I recommend this method when you're definite that you will use that data a lot (STILL RISKY), but this method is like goddess of data handling :).
Create a NSObject subclass and call it DataManager.swift (I call it data manager cause it handle data.) as following:
import UIKit
class DataManager: NSObject {
//Store Data Globally
static var someData: Boo! //This Boolean, you can choose whatever you want.
}
the static is what keep your data live.
Now you can store and receive someData from anywhere like you handle any data type like this.
//Store
DataManager.someData = true
//Receive
print(DataManager.someData)
Challenges:
You can also use
Keychain
Sergey Kargopolov will walk you through how to use a third party to use swift keychain. Otherwise, you can take even harder challenge and create one yourself :P .
Key-Value Data in iCloud
Use CoreData to save it in a database, then you can perform a fetch request to get it back out of the database.
Very simple look it up here:
https://www.youtube.com/watch?v=3IDfgATVqHw