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
Related
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.
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")
The question might sound complicated, so let me ease the stress*
Lets say I have 2 tab bar tabs (Home1, Home2)
Both (Home1, Home2) have navigational controllers with two view controllers each
Home1(Navigation controller -> VC11 -> VC12)
Home2 (Navigation controller -> VC21 -> VC22)
Easy right? Well, not quite
What I want to do is pass data from [Home1: VC12 to Home2: VC22].
My coding efforts:
tabBarController!.selectedIndex = 1
self.navigationController!.popToViewController(navigationController!.viewControllers[1] as! (Home2: VC22), animated: false)
let navController = self.tabBarController?.viewControllers![1] as! UINavigationController
navController.popToViewController((Home2: VC22) as! UIViewController, animated: true)
for oneView in (self.navigationController?.viewControllers)! {
if (oneView.isKind(of: (Home2: VC22).classForCoder())) {
let friendView = oneView as! (Home2: VC22)
friendView.testing = "Worked?"
}
}
ANYHELP IS WELCOMED!! Total hours spent: 8hrs
Your pass data task is going though this process
V12 --(pop)--> V11 --(switch)--> V21 --(push)--> V22
If you choose to pass data, you will need to pass it though all these three transactions and that's lots of coding and it's hard to practice.
Instead of passing data around, a better way to accomplish your goal is to store the data in V12, and then load it from V22. So now all you need to worry about is how to transfer user from V12 to V22.
You only need two lines of code to store and read data from UserDefaults
On your V12, before you are doing the above transactions, first save your data like this
UserDefaults.standard.set("yourStringData", forKey: "data")
Then when you reach VC22, from viewDidLoad, read stored info in this way
UserDefaults.standard.string(forKey: "data")
For your view transaction part, popToViewController is for going from a child view controller to it's parent. So when you switch your tab and get the UINavigationController, the topViewController must be VC21. So to go to VC22 given that you connect them though a storyboard segue, simply call it like this
let navController = self.tabBarController?.viewControllers![1] as! UINavigationController
let VC21 = navController.topViewController!
VC21.performSegue(withIdentifier: "segue", sender: nil)
You could also subclass your tabbar and create a variable to store your data there. Then both VC's would have access to the data. This way also alleviates the possible need for a singleton.
It sounds like you need to rethink your approach. It depends on the way you setup your app but it makes sense to store this data somewhere else besides directly passing it from one VC to another. Here are some options:
Singleton that stores your data and you pass that around from one VC to another so that if VC12 stores data in the Singleton, then VC22 can access it easily since it also has access to the singleton.
Have the Container View Controller store the data to be shared amongst its children view controllers. So, in this example, the TabBarController can store this data.
Use UserDefaults as a poor-mans Singleton/Persistence solution.
Use a full blown Data Persistence layer using SQLite, Core Data, or Realm for example to store and retrieve data.
... there are others but I think one of these solutions can work well for you depending on your needs.
This is all purely for educational purposes, to help me get a better understanding of how Parse as well as Swift operates.
I would like to make it so a user is only able to like an item once (not being able to hit a button multiple times), as currently, I'm utilizing an anonymous system with Parse.
Would I essentially use an if method with PFUser.CurrentUser() in the likeButton method to halt a user from hitting like again or would I use NSUserDefaults?
I'm not able to post code currently as I'm not near my laptop, however I could later if it helps. Still curious if I could get some info before that however.
Sample code I found on here from a previous question, which essentially implements the same idea.
#IBAction func likeButton(sender: AnyObject) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count")
object.saveInBackground()
self.tableView.reloadData()
}
Would I call NSUsersDefaults to stunt the user from hitting it more than once?
Instead of calling saveInBackground(), you'd better call the method saveInBackgroundWithBlock: instead. So the strategy is very simple:
First of all, define a 'busy' flag for the object (For example: savingInBackground) and store it wherever you like ( If you are showing 1 item then simply declare a Bool property / If you are showing a list of Item then declare a Dictionary with format ["objectID/Index": Bool]). This flag should be set to true for the item being saved in the background.
Whenever use taps on a Like button
If current item's savingInBackground flag is true, then do nothing
Else:
Set item's savingInBackground to true
Increase Like count and Call saveInBackgroundWithBlock:
In the completion block of saveInBackgroundWithBlock:, set savingInBackground back to false.
I am on train now so I can't write example code, but I hope that it's clear enough to help you to achieve what you want.
I am trying to use swift's shouldPerformSegueWithIdentifier() method, but it accepts 2 arguments. These are (identifier: String!, sender:AnyObject)
My main goal is to execute the code when pressing a login button in my storyboard, and depending of a series of checks return TRUE or FALSE, depending if whether the correct username and password were provided. So here are my questions:
What am I supposed to use as the identifier? Apple's documentation it explains that the identifier is a string that identifies the triggered segue. So suppose that my segue had the name of loginSegueProcess. How could I use it in my ViewController tat is assigned to my UIView? The thing is that I declare the method in my code and it requires me to specify both arguments (identifier & sender). How could I provide the arguments?
Will this method actually fulfill my needs? By that I mean if it will indeed stop the segue transition whenever my Login button is clicked and depending on whether the correct credentials were provided it is going to take you to the next View or it will show, say for example, an AlertView.
Finally, I was thinking that the performSegueWithIdentifier(args) method would help me as well. Does anybody know the difference between them?
Thanks a lot in advance!
isn't it what you want to do?
override func shouldPerformSegueWithIdentifier(identifier: String!, sender: AnyObject!) -> Bool {
if identifier == "LoginSuccessSegue" { // you define it in the storyboard (click on the segue, then Attributes' inspector > Identifier
var segueShouldOccur = /** do whatever you need to set this var to true or false */
if !segueShouldOccur {
println("*** NOPE, segue wont occur")
return false
}
else {
println("*** YEP, segue will occur")
}
}
// by default, transition
return true
}
You may not invoke shouldPerformSegueWithIdentifier() method by yourself. It will be automatically called just before transition to the next view giving a chance to determine wether the transition should take place or. You may conditionally return YES/NO from this method. If your condition does't involve any sever call,a simple logical checking this method will be enough for you.
performSegueWithIdentifier() is used to invoke a segue programmatically. Consider the above case with a network call, you may return NO from shouldPerformSegueWithIdentifier() initially since authentication is going on. After getting the response from server if it success you can call the segue to execute with performSegueWithIdentifier (Here the identifier is the ID you have given in the storyboard). Before make sure you are supposed to return YES from shouldPerformSegueWithIdentifier().
Now a third case if your segue is connecting from the login button(You have to connect it from the controller itself). The checking of shouldPerformSegueWithIdentifier is no more required. You can just call the segue with performSegueWithIdentifier() after getting the success response from server