NSDictionary becomes NSCFString when I save to NSUserDefaults in Swift - swift

NSDictionary becomes NSCFString when I save to NSUserDefaults:
class SecondViewController: UIViewController {
#IBOutlet var questionforsave: UITextField!
#IBOutlet var answerforsave: UITextField!
var answersSaved = [String:String]()
#IBAction func savePressed(sender: AnyObject) {
if questionforsave.text.isEmpty || answerforsave.text.isEmpty{
let alert = UIAlertView()
alert.title = "Empty fields"
alert.message = "Please Enter Text In Both Text Fields"
alert.addButtonWithTitle("Ok")
alert.show()
}else{
println("is ok")
var answerSave = answerforsave.text
var questionSave = questionforsave.text
answersSaved[questionSave] = answerSave
let alert = UIAlertView()
alert.title = "Success!"
alert.message = "It worked!"
alert.addButtonWithTitle("Awesome!")
alert.show()
NSUserDefaults.standardUserDefaults().setObject(answersSaved, forKey: "answersSaved")
println(answersSaved)
}
}
override func viewDidLoad() {
super.viewDidLoad()
println(answersSaved)
if NSUserDefaults.standardUserDefaults().objectForKey("answersSaved") != nil {
answersSaved = NSUserDefaults.standardUserDefaults().objectForKey("answersSaved") as! [String:String]
}else{
println("No Defaults")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
//do the stuff here
resignFirstResponder()
return true
}
}

Your issue is that you are setting a string and then trying to retrieve a dictionary, but I would recommend using if let to retrieve the dictionary and then optionally cast it to be [String: String]:
var answersSaved = [String: String]()
override func viewDidLoad() {
super.viewDidLoad()
if let answersFromDefaults = NSUserDefaults.standardUserDefaults().dictionaryForKey("answersSaved") as? [String: String] {
answersSaved = answersFromDefaults
} else {
// Failed to retrieve value from NSUserDefaults
}
answersSaved = ["test": "a"] // Set answersSaved somewhere in your code
}
#IBAction func saveButtonPressed(sender: UIBarButtonItem) {
NSUserDefaults.standardUserDefaults().setObject(answersSaved, forKey: "answersSaved")
}

NSUserDefaults.standardUserDefaults().setObject("answersSaved", forKey: "answersSaved")
You're writing the string "answersSaved" into NSUserDefaults. I assume you meant answersSaved.

You should cast it optionally as a [String:String] dictionary.
Try this:
if let answersFromDefaults = NSUserDefaults.standardUserDefaults().dictionaryForKey("answersSaved") as? [String: String] {
answersSaved = answersFromDefaults
} else {
// Failed to retrieve value from NSUserDefaults
}

When you load the dictionary into NSUserDefaults you should do it like this:
NSUserDefaults.standardUserDefaults().setObject(answersSaved, forKey: "answersSaved")
This saves it as a generic NSObject. When you want to read out the data though use the command:
answersSaved = NSUserDefaults.standardUserDefaults().dictionaryForKey("answersSaved")
This should specify that the object is a Dictionary

Related

JSON Data is not fetched to Signuser model class properties to view properties in segued view controller labels in viewdidload

I have a model class of all string variables which i need to display in home view controller when user is successfully logged in.
I have created a seperate function to fetch and assign stuffs from user profile api and assign to model class.
and it's called in login function.
but after the segue to next view controller,Model class variables are still blank in it's viewdidload.(consider it as any viewcontroller )
import UIKit
import Alamofire
import SwiftyJSON
class LoginViewController: UIViewController {
var countries = [String]()
var cities = [String]()
let manager = APIManager()
#IBOutlet var txtUsername: UITextField!
#IBOutlet var txtPassword: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func ForgotPasswordAction(_ sender: UIButton) {
}
#IBAction func LoginButtonAction(_ sender: UIButton) {
let username = self.txtUsername.text
let password = self.txtPassword.text
if (username?.isEmpty)! || (password?.isEmpty)!{
self.showAlertWith(title: "Empty Username / Password", message: "Please check if username or password is entered")
}
else {
if Connectivity.isConnectedToInternet{
let parameter:Parameters = ["userItsId":username!,"password":password!]
manager.parsing2(url: BaseURL.login, parameter: parameter) { (JSON, Status) in
if Status { //login success
self.fetchUserProfile()
if JSON["status"] == "true"{
self.performSegue(withIdentifier: "login", sender:self)
}
else{
print("login failed")
}
}
else {
print("error occured,try again later")
}
}
}
else {
self.showAlertWith(title: "No Internet", message: "Please make sure that your device is connected to internet")
}
}
}
#IBAction func NotMemberAction(_ sender: UIButton) {
performSegue(withIdentifier: "register", sender: self)
}
#IBAction func SkipButtonAction(_ sender: UIButton) {
if Connectivity.isConnectedToInternet {
user.isLoggedin = false
performSegue(withIdentifier: "skip", sender: self )
}
else {
self.showAlertWith(title: "Connectivity Error", message: "Please check your connection and make sure that you are connected to the internet")
}
}
func fetchUserProfile(){
let userid = txtUsername.text
let parameter:Parameters = ["userItsId":userid!]
manager.parsing2(url: BaseURL.profile, parameter: parameter) { (JSON, Status) in
if Status{
let dict = JSON.dictionaryObject!
let data = dict["data"] as! [String:String]
let username = data["userName"]
let email = data["email"]
let UserId = data["userId"]
let nationality = data["nationality"]
let country = data["country"]
let mCity = data["mCity"]
let phoneNo = data["phoneNo"]
let dawatTitle = data["dawatTitle"]
let itsId = data["itsId"]
signUser.name = username!
signUser.email = email!
signUser.userID = UserId!
signUser.nationality = nationality!
signUser.country = country!
signUser.mCity = mCity!
signUser.phone = phoneNo!
signUser.dawatName = dawatTitle!
signUser.ItsId = itsId!
}
else {
print("fetching failed")
}
}
}
}

Why does my segue not wait until completion handler finished?

I have a page based app, using RootViewController, ModelViewController, DataViewController, and a SearchViewController.
In my searchViewController, I search for an item and then add or remove that Item to an array which is contained in a Manager class(and UserDefaults), which the modelViewController uses to instantiate an instance of DataViewController with the correct information loaded using the dataObject. Depending on whether an Item was added or removed, I use a Bool to determine which segue was used, addCoin or removeCoin, so that the RootViewController(PageView) will show either the last page in the array, (when a page is added) or the first (when removed).
Everything was working fine until I ran into an error which I can not diagnose, the problem is that when I add a page, the app crashes, giving me a "unexpectadely found nil when unwrapping an optional value"
This appears to be the problem function, in the searchViewController 'self.performSegue(withIdentifier: "addCoin"' seems to be called instantly, even without the dispatchque:
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
CGPrices.shared.getData(arr: true, completion: { (success) in
print(Manager.shared.coins)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
})
}
searchBar.text = ""
}
Meaning that In my DataViewController, this function will find nil:
func getIndex() {
let index = CGPrices.shared.coinData.index(where: { $0.id == dataObject })!
dataIndex = index
}
I can't find out why it does not wait for completion.
I also get this error about threads:
[Assert] Cannot be called with asCopy = NO on non-main thread.
which is why I try to do the push segue using dispatch que
Here is my searchViewController full code:
import UIKit
class SearchViewController: UIViewController, UISearchBarDelegate {
let selectionLabel = UILabel()
let searchBar = UISearchBar()
let addButton = UIButton()
let removeButton = UIButton()
var filteredObject: [String] = []
var dataObject = ""
var isSearching = false
//Add Button Action.
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
CGPrices.shared.getData(arr: true, completion: { (success) in
print(Manager.shared.coins)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
})
}
searchBar.text = ""
}
//Remove button action.
#objc func removeButtonActon(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.removeCoin(coin: dataObject)
self.performSegue(withIdentifier: "addCoin", sender: self)
}
searchBar.text = ""
}
//Prepare for segue, pass removeCoinSegue Bool depending on remove or addCoin.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addCoin" {
if let destinationVC = segue.destination as? RootViewController {
destinationVC.addCoinSegue = true
}
} else if segue.identifier == "addCoin" {
if let destinationVC = segue.destination as? RootViewController {
destinationVC.addCoinSegue = false
}
}
}
//Remove button action.
#objc func removeButtonAction(sender: UIButton!) {
if Manager.shared.coins.count == 1 {
removeAlert()
} else {
Manager.shared.removeCoin(coin: dataObject)
print(Manager.shared.coins)
print(dataObject)
searchBar.text = ""
self.removeButton.isHidden = true
DispatchQueue.main.async {
self.performSegue(withIdentifier: "removeCoin", sender: self)
}
}
}
//Search/Filter the struct from CGNames, display both the Symbol and the Name but use the ID as dataObject.
func filterStructForSearchText(searchText: String, scope: String = "All") {
if !searchText.isEmpty {
isSearching = true
filteredObject = CGNames.shared.coinNameData.filter {
// if you need to search key and value and include partial matches
// $0.key.contains(searchText) || $0.value.contains(searchText)
// if you need to search caseInsensitively key and value and include partial matches
$0.name.range(of: searchText, options: .caseInsensitive) != nil || $0.symbol.range(of: searchText, options: .caseInsensitive) != nil
}
.map{ $0.id }
} else {
isSearching = false
print("NoText")
}
}
//Running filter function when text changes.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filterStructForSearchText(searchText: searchText)
if isSearching == true && filteredObject.count > 0 {
addButton.isHidden = false
dataObject = filteredObject[0]
selectionLabel.text = dataObject
if Manager.shared.coins.contains(dataObject) {
removeButton.isHidden = false
addButton.isHidden = true
} else {
removeButton.isHidden = true
addButton.isHidden = false
}
} else {
addButton.isHidden = true
removeButton.isHidden = true
selectionLabel.text = "e.g. btc/bitcoin"
}
}
override func viewDidLoad() {
super.viewDidLoad()
//Setup the UI.
self.view.backgroundColor = .gray
setupView()
}
override func viewDidLayoutSubviews() {
}
//Hide keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
//Alerts
func removeAlert() {
let alertController = UIAlertController(title: "Can't Remove", message: "\(dataObject) can't be deleted, add another to delete \(dataObject)", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
func Duplicate() {
let alertController = UIAlertController(title: "Duplicate", message: "\(dataObject) is already in your pages!", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
func max() {
let alertController = UIAlertController(title: "Maximum Reached", message: "\(dataObject) can't be added, you have reached the maximum of 5 coins. Please delete a coin to add another.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
and here is the DataViewController
import UIKit
class DataViewController: UIViewController {
#IBOutlet weak var dataLabel: UILabel!
//Variables and Objects.
//The dataObject carries the chosen cryptocurrencies ID from the CoinGecko API to use to get the correct data to load on each object.
var dataObject = String()
//The DefaultCurrency (gbp, eur...) chosen by the user.
var defaultCurrency = ""
//The Currency Unit taken from the exchange section of the API.
var currencyUnit = CGExchange.shared.exchangeData[0].rates.gbp.unit
var secondaryUnit = CGExchange.shared.exchangeData[0].rates.eur.unit
var tertiaryUnit = CGExchange.shared.exchangeData[0].rates.usd.unit
//Index of the dataObject
var dataIndex = Int()
//Objects
let cryptoLabel = UILabel()
let cryptoIconImage = UIImageView()
let secondaryPriceLabel = UILabel()
let mainPriceLabel = UILabel()
let tertiaryPriceLabel = UILabel()
//Custom Fonts.
let customFont = UIFont(name: "AvenirNext-Heavy", size: UIFont.labelFontSize)
let secondFont = UIFont(name: "AvenirNext-BoldItalic" , size: UIFont.labelFontSize)
//Setup Functions
//Get the index of the dataObject
func getIndex() {
let index = CGPrices.shared.coinData.index(where: { $0.id == dataObject })!
dataIndex = index
}
//Label
func setupLabels() {
//cryptoLabel from dataObject as name.
cryptoLabel.text = CGPrices.shared.coinData[dataIndex].name
//Prices from btc Exchange rate.
let btcPrice = CGPrices.shared.coinData[dataIndex].current_price!
let dcExchangeRate = CGExchange.shared.exchangeData[0].rates.gbp.value
let secondaryExchangeRate = CGExchange.shared.exchangeData[0].rates.eur.value
let tertiaryExchangeRate = CGExchange.shared.exchangeData[0].rates.usd.value
let realPrice = (btcPrice * dcExchangeRate)
let secondaryPrice = (btcPrice * secondaryExchangeRate)
let tertiaryPrice = (btcPrice * tertiaryExchangeRate)
secondaryPriceLabel.text = "\(secondaryUnit)\(String((round(1000 * secondaryPrice) / 1000)))"
mainPriceLabel.text = "\(currencyUnit)\(String((round(1000 * realPrice) /1000)))"
tertiaryPriceLabel.text = "\(tertiaryUnit)\(String((round(1000 * tertiaryPrice) / 1000)))"
}
//Image
func getIcon() {
let chosenImage = CGPrices.shared.coinData[dataIndex].image
let remoteImageUrl = URL(string: chosenImage)
guard let url = remoteImageUrl else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
DispatchQueue.main.async {
self.cryptoIconImage.image = UIImage(data: data)
}
}
}.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
// for family in UIFont.familyNames.sorted() {
// let names = UIFont.fontNames(forFamilyName: family)
// print("Family: \(family) Font names: \(names)")
// }
// Do any additional setup after loading the view, typically from a nib.
self.setupLayout()
self.getIndex()
self.setupLabels()
self.getIcon()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.dataLabel!.text = dataObject
view.backgroundColor = .lightGray
}
}
Edit: CGPrices Class with getData method:
import Foundation
class CGPrices {
struct Coins: Decodable {
let id: String
let name: String
let symbol: String
let image: String
let current_price: Double?
let low_24h: Double?
//let price_change_24h: Double?
}
var coinData = [Coins]()
var defaultCurrency = ""
var coins = Manager.shared.coins
var coinsEncoded = ""
static let shared = CGPrices()
func encode() {
for i in 0..<coins.count {
coinsEncoded += coins[i]
if (i + 1) < coins.count { coinsEncoded += "%2C" }
}
print("encoded")
}
func getData(arr: Bool, completion: #escaping (Bool) -> ()) {
encode()
let urlJSON = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=\(coinsEncoded)"
guard let url = URL(string: urlJSON) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let coinsData = try JSONDecoder().decode([Coins].self, from: data)
self.coinData = coinsData
completion(arr)
} catch let jsonErr {
print("error serializing json: \(jsonErr)")
print(data)
}
}.resume()
}
func refresh(completion: () -> ()) {
defaultCurrency = UserDefaults.standard.string(forKey: "DefaultCurrency")!
completion()
}
}
I figured it out.
The problem was inside my getData method I was not updated the coins array:
var coinData = [Coins]()
var defaultCurrency = ""
var coins = Manager.shared.coins
var coinsEncoded = ""
static let shared = CGPrices()
func encode() {
for i in 0..<coins.count {
coinsEncoded += coins[i]
if (i+1)<coins.count { coinsEncoded+="%2C" }
}
print("encoded")
}
I needed to add this line in getData:
func getData(arr: Bool, completion: #escaping (Bool) -> ()) {
//Adding this line to update the array so that the URL is appended correctly.
coins = Manager.shared.coins
encode()
let urlJSON = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=\(coinsEncoded)"
This would fix the finding nil in the DataViewController, but the app would still crash do to updating UI Elements on a background thread, as the segue was called inside the completion handler of the getData method. to fix this, I used DispatchQue.Main.Async on the segue inside the getData method in the addButton function, to ensure that everything is updated on the main thread, like so:
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
print("starting")
CGPrices.shared.getData(arr: true) { (arr) in
print("complete")
print(CGPrices.shared.coinData)
//Here making sure it is updated on main thread.
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
}
}
searchBar.text = ""
}
Thanks for all the comments as they helped me to figure this out, and I learned a lot in doing so. Hopefully this can help someone else in their thought process when debugging, as one can get so caught up in one area of a problem, and forget to take a step back and look to other areas.

enable a button if matches the last date stored +1

I am fairly new to Swift, but getting better.
I have managed to disable a button and store the date. And at this point I have reached the end of my knowledge, so I am hoping someone can help.
The button then needs to be enabled the next day by checking against the date stored, so the user can only use the function once per day.
code is as follows;
import Foundation
import UIKit
class tryForAFiver : UIViewController {
#IBOutlet weak var drinkImage: UIImageView!
#IBOutlet weak var redeemButton: UIButton!
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
#IBAction func redeemButton(_ sender: Any) {
let cocktailNumber = arc4random_uniform(32)
drinkImage.image = UIImage(named: "cocktailList\(cocktailNumber)")
let userDefaults = UserDefaults.standard
if var timeList = userDefaults.object(forKey: "timeList") as? [NSDate]
{
timeList.append(NSDate())
userDefaults.set(timeList, forKey: "timeList")
}
else
{
userDefaults.set([NSDate()], forKey: "timeList")
}
userDefaults.synchronize()
if let timeList = UserDefaults.standard.object(forKey: "timeList") as? [NSDate]
{
print(timeList)
}
self.redeemButton.isEnabled = false
}
}
thanks in advance for any help.
I made some changes to your code. Is it OK to use Date() instead of NSDate()? It's easier to work with in Swift.
Button action:
#IBAction func redeemButton(_ sender: Any) {
let userDefaults = UserDefaults.standard
if var timeList = userDefaults.object(forKey: "timeList") as? [Date]
{
timeList.append(Date())
userDefaults.set(timeList, forKey: "timeList")
}
else
{
userDefaults.set([Date()], forKey: "timeList")
}
userDefaults.synchronize()
if let timeList = UserDefaults.standard.object(forKey: "timeList") as? [Date]
{
print(timeList)
}
self.redeemButton.isEnabled = false
}
And on viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if let timeList = UserDefaults.standard.object(forKey: "timeList") as? [Date], let lastDay = timeList.last
{
if Calendar.current.isDateInToday(lastDay) {
self.redeemButton.isEnabled = false
}
else {
self.redeemButton.isEnabled = true
}
}
}
This should get you on the right track. A word of warning: neither UserDefaults() nor Date() are safe for doing this kind of thing. Both are easily modified by the client. You should do a server check also if it's important.

How to clear the information from the Label.text?

I am developing a QR code reader application. Hier is my code:
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var qrCodeframeView: UIView?
#IBOutlet weak var CancelButton: UIButton!
#IBOutlet weak var Label: UILabel!
override func viewDidLoad() {
CancelButton.hidden = true
Label.hidden = true
super.viewDidLoad()
// 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.
}
#IBAction func ScanMe(sender: AnyObject) {
CancelButton.hidden = false
Label.hidden = false
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
var error: NSError?
let input: AnyObject!
do {
input = try AVCaptureDeviceInput (device: captureDevice)
} catch let error1 as NSError{
error = error1
input = nil
}
if (error != nil){
print ("\(error?.localizedDescription)")
return
}
captureSession = AVCaptureSession()
captureSession?.addInput(input as! AVCaptureInput)
let captureMetadatOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadatOutput)
captureMetadatOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
captureMetadatOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
captureSession?.startRunning()
view.bringSubviewToFront(Label)
view.bringSubviewToFront(CancelButton)
qrCodeframeView = UIView()
qrCodeframeView?.layer.borderColor = UIColor.greenColor().CGColor
qrCodeframeView?.layer.borderWidth = 2
view.addSubview(qrCodeframeView!)
view.bringSubviewToFront(qrCodeframeView!)
}
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
if metadataObjects == nil || metadataObjects.count == 0 {
qrCodeframeView?.frame = CGRectZero
Label.text = "No QR code detected"
return
}
let metadateObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if metadateObj.type == AVMetadataObjectTypeQRCode {
let BarcodeObject = videoPreviewLayer?.transformedMetadataObjectForMetadataObject(metadateObj as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject
qrCodeframeView?.frame = BarcodeObject.bounds
if metadateObj.stringValue != nil {
Label.text = metadateObj.stringValue
captureSession?.stopRunning()
}
}
}
#IBAction func Cancel(sender: AnyObject) {
CancelButton.hidden = true
Label.hidden = true
captureSession?.stopRunning()
qrCodeframeView?.removeFromSuperview()
videoPreviewLayer?.removeFromSuperlayer()
}
#IBAction func Open(sender: AnyObject) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var PC : SecondSecondViewController = segue.destinationViewController as! SecondSecondViewController
PC.label1 = Label.text!
}
}
The problem is when I click the cancel button and go back to the previous viewcontroller, when I reopen the qr code scanner I see the last scanned code, displayed in the Label.text. Would you please help me how to clear the label and do not display the old code, because these codes must be used only once and if the users see the codes they will be able to use them again.
If you want without adding other callbacks:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var PC : SecondSecondViewController = segue.destinationViewController as! SecondSecondViewController
PC.label1 = Label.text!
Label.text = ""
}
otherwise you have to catch the unwind segue when you come back from SecondSecondViewController and there set Label.text = ""
Just add this to where you exit from the QR (press cancel):
label.text = ""

NSUserDefaults not saving data (Swift)

I am trying to save inputs from various text fields using NSUserDefaults:
#IBAction func continue2save(sender: AnyObject) {
let stringy1: NSString = mcweightTF.text!
let stringy2: NSString = mcnumTF.text!
NSUserDefaults.standardUserDefaults().setObject(stringy1, forKey: "savemcw")
NSUserDefaults.standardUserDefaults().setObject(stringy2, forKey: "savemcn")
NSUserDefaults.standardUserDefaults().synchronize()
}
#IBAction func calculate(sender: AnyObject) {
let load1: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("savemcw")
calcLabel.text = String(load1)
}
However "load1"'s value is always nil. I have attempted almost every configuration of implementing short-term storage through NSUserDefaults, however the value stored is always nil.
Try this,
#IBAction func continue2save(sender: AnyObject) {
let stringy1 = mcweightTF.text!
let stringy2 = mcnumTF.text!
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("stringy1", forKey: "savemcw")
defaults.setObject("stringy2", forKey: "savemcn")
}
#IBAction func calculate(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()
let stringy1 = defaults.stringForKey("savemcw")
// Optional Chaining for stringy1
if let stringy = stringy1 {
calcLabel.text = stringy
}
}