lost data in the coreData - swift

My app will show teacher shedule, in the first controller teacher need to choose the right pair (first, second, third) and then write nessesary data (like what the subject name, room, number of group) now in my code if i write data in first pair and save, it will show to me, but if i write data in second pair and choose save button, the previous data in first pair is lost, so i have a problem with losing data, this is code for controller where i choose pair:
class ChoosePair: UIViewController {
enum choosePair: Int{
case FirstPair = 21
case SecondPair = 22
case ThirdPair = 23
case FourPair = 24
}
#IBAction func PairButtons(_ sender: UIButton){
guard let day = choosePair.init(rawValue: sender.tag) else { return }
switch day {
case .FirstPair:
let FirstPair = self
UserDefaults.standard.set(21, forKey: "pairId")
performSegue(withIdentifier: "SheduleTeacher", sender: self)
break
case .SecondPair:
let SecondPair = self
UserDefaults.standard.set(22, forKey: "pairId")
performSegue(withIdentifier: "SheduleTeacher", sender: SecondPair)
break
case .ThirdPair:
let ThirdPair = self
UserDefaults.standard.set(23, forKey: "pairId")
performSegue(withIdentifier: "SheduleTeacher", sender: ThirdPair)
break
case .FourPair:
let FourPair = self
UserDefaults.standard.set(24, forKey: "pairId")
performSegue(withIdentifier: "SheduleTeacher", sender: FourPair)
break
}
}
}
And the code for second controller(where i write data and save it in CoreData)
class SheduleTeacher: UIViewController {
var pairId = UserDefaults.standard.integer(forKey: "pairId")
#IBOutlet weak var subjectLabel: UILabel!
#IBOutlet weak var roomLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
#IBOutlet weak var groupLabel: UILabel!
#IBOutlet weak var captainLabel: UILabel!
#IBOutlet weak var subjectField: UITextField!
#IBOutlet weak var roomField: UITextField!
#IBOutlet weak var timeField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var groupField: UITextField!
#IBOutlet weak var captainField: UITextField!
let appDelegate = UIApplication.shared.delegate as! AppDelegate
override func viewDidLoad() {
super.viewDidLoad()
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
subjectField.text = data.value(forKey: "subject\(pairId)") as? String
roomField.text = data.value(forKey: "room\(pairId)") as? String
timeField.text = data.value(forKey: "time\(pairId)") as? String
emailField.text = data.value(forKey: "emailGroup\(pairId)") as? String
groupField.text = data.value(forKey: "group\(pairId)") as? String
captainField.text = data.value(forKey: "captain\(pairId)") as? String
}
} catch {
print("Failed")
}
subjectLabel.layer.borderWidth = 1.0
roomLabel.layer.borderWidth = 1.0
timeLabel.layer.borderWidth = 1.0
emailLabel.layer.borderWidth = 1.0
groupLabel.layer.borderWidth = 1.0
captainLabel.layer.borderWidth = 1.0
}
#IBAction func saveButton(_ sender: UIButton) {
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Users", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
newUser.setValue(self.subjectField!.text, forKey: "subject\(pairId)")
newUser.setValue(self.roomField!.text, forKey: "room\(pairId)")
newUser.setValue(self.timeField!.text, forKey: "time\(pairId)")
newUser.setValue(self.emailField!.text, forKey: "emailGroup\(pairId)")
newUser.setValue(self.groupField!.text, forKey: "group\(pairId)")
newUser.setValue(self.captainField!.text, forKey: "captain\(pairId)")
do {
try context.save()
} catch {
print("Failed saving")
}
}
}
And photo what I now have in CoreData
photo

Predicates are used to limit the fetch to only get certain entities.
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
Does not set a predicate so it always returns all the Users entities there are. The following has you iterate over every entity, that's why there is a for-loop.
for data in result as! [NSManagedObject] {
Here is an example how you can use a predicate to only get entities with entity.pairId == pairId.
override func viewDidLoad() {
super.viewDidLoad()
let context = AppDelegate.shared.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "pairId = %#", argumentArray: [pairId])
do {
let results = try context.fetch(request)
guard results.count == 1 else {
fatalError("Bad count: \(results.count)")
}
guard let data = results.first! as? NSManagedObject else {
fatalError("No NSManagedObject")
}
context.performAndWait {
subjectField.text = data.value(forKey: "subject\(pairId)") as? String
roomField.text = data.value(forKey: "room\(pairId)") as? String
timeField.text = data.value(forKey: "time\(pairId)") as? String
emailField.text = data.value(forKey: "emailGroup\(pairId)") as? String
groupField.text = data.value(forKey: "group\(pairId)") as? String
captainField.text = data.value(forKey: "captain\(pairId)") as? String
}
} catch {
print("Failed")
}
// ...
}
The entity must of course have said attribute pairId for the predicate to work.
You would do something like this in the save() method too. There you could update the retrieved Users entity/create a new one if one does not exist.
One alternative is to delete the old one if one so exists and always create a new one on save.
The other alternative to "create a new one if one does not exist" is to pre-create for all four buttons and then fetch the entities on save and update them there. You would however have to check on startup too if they exist already else you would create on every startup four.

In your saveButton func you create a new Users instance every time which mean data from pair two will not be written together with data for pair one but as a separate record. You need to update the existing object, the one you fetched in viewDidLoad, instead. (I very much doubt any data is lost)
That being said I think you need to rethink your design, having duplicate (or more) fields in the same entity looks like an awkward design that will be hard to maintain. A better solution would be to only have one group attribute, one subject attribute and so on and complement it with an attribute that holds the pairId.
Also, why is the entity name Users, it seems to hold no kind of user id?

Related

Displaying Username in Swift and FireBase

I'm trying to display the users username that stored in firebase. I'm not sure if Im saving the username correctly or if that's even the problem. I can't seem to access the data or display it at all. Any tips? I have a screenshot of the Cloud Firestore attached.
SignupViewController
import UIKit
import FirebaseAuth
import Firebase
import AVKit
import FirebaseFirestore
class SignUpViewController: UIViewController {
var videoPlayer:AVPlayer?
var videoPlayerLayer:AVPlayerLayer?
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var BackButton: UIButton!
#IBOutlet weak var UserNameTextField: UITextField!
#IBOutlet weak var signUpButton: UIButton!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing))
view.addGestureRecognizer(tap)
// Do any additional setup after loading the view.
setupElements()
}
func setupElements(){
//hides the error label
errorLabel.alpha = 0
//styles the text and buttons
Utilities.styleTextField(UserNameTextField)
Utilities.styleTextField(firstNameTextField)
Utilities.styleTextField(lastNameTextField)
Utilities.styleTextField(passwordTextField)
Utilities.styleTextField(emailTextField)
Utilities.styleFilledButton(signUpButton)
}
/*
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
// this function makes sure all data is good
func validateFields() -> String?
{
//make sure fields are filled
if firstNameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || lastNameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || emailTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" || UserNameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) == ""
{
return "Please fill all fields"
}
let cleanPassword = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
if Utilities.isPasswordValid(cleanPassword) == false{
return "Needs 8 charaters, number, and special charater"
}
return nil
}
#IBAction func signUpTapped(_ sender: Any) {
//validate fields
let error = validateFields()
if error != nil{
showError(error!)
}
else{
let firstName = firstNameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let lastName = lastNameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let email = emailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let username = UserNameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
//create user
Auth.auth().createUser(withEmail: email, password: password) { result, err in
if err != nil{
self.showError("Error creating user")
}
else
{
//User is stored sucessfully, store the first and last name
let database = Firestore.firestore()
database.collection("UserInfo").addDocument(data: ["firstname": firstName,"email": email, "lastname": lastName, "username": username, "uid": result!.user.uid]) {(error) in
if error != nil
{
self.showError("First name and last name couldnt be saved.")
}
}
self.transitionToHome()
}
}
}
}
func showError(_ message:String){
errorLabel.text = message
errorLabel.alpha = 1
}
func transitionToHome(){
let homeViewController = storyboard?.instantiateViewController(identifier: Constants.StoryBoard.homeViewController) as?
HomeViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
override func viewWillAppear(_ animated: Bool) {
//Set up video in background
setUpVideo()
}
func setUpVideo(){
//Get path to resource bundle
let bundlePath = Bundle.main.path(forResource: "IMG_7211 2", ofType: "mov")
guard bundlePath != nil else{
return
}
//create the url from it
let url = URL(fileURLWithPath: bundlePath!)
//Create The video Player item
let item = AVPlayerItem(url: url)
//create the player
videoPlayer = AVPlayer(playerItem: item)
//create the layer
videoPlayerLayer = AVPlayerLayer(player: videoPlayer!)
//adjust the size and frame
videoPlayerLayer?.frame = CGRect(x: -self.view.frame.size.width*1.5, y:0, width: self.view.frame.size.width*4, height: self.view.frame.size.height)
view.layer.insertSublayer(videoPlayerLayer!, at: 0)
//add and play
videoPlayer?.playImmediately(atRate: 0.8)
}
}
CurrentUser.swift
import Foundation
struct CurrentUser{
let uid: String
let name: String
let email: String
let profilepictureURL:String
init(uid: String, dictionary: [String: Any]){
self.uid = uid
self.name = dictionary["username"] as? String ?? ""
self.email = dictionary["email"] as? String ?? ""
self.profilepictureURL = dictionary["profilepictureURL"] as? String ?? ""
}
}
ProfileViewController
import UIKit
import Firebase
import FirebaseAuth
import FirebaseInstallations
import FirebaseFirestore
import FirebaseStorage
import FirebaseDatabase
class ProfileViewController: UIViewController {
#IBOutlet weak var SignOut: UIButton!
#IBOutlet weak var UserName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
UserNameLabel()
// Do any additional setup after loading the view.
}
func UserNameLabel()
{
if Auth.auth().currentUser != nil
{
guard let uid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value) { (snapshot) in
guard let dict = snapshot.value as? [String: Any] else {return}
let user = CurrentUser(uid: uid, dictionary: dict)
self.UserName.text = user.username
}
}
}
#IBAction func SignOut(_ sender: Any) {
if Auth.auth().currentUser != nil {
do {
try Auth.auth().signOut()
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Vc")
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true, completion: nil)
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
}
The problem is you are saving the data to Firebase Firestore, and then trying to access it from firebase real time database. Firebase Realtime Database and Firebase Firestore are 2 completely different backend servers and you are trying to use both at the same time. You need to pick only 1 and stick with it.
You are saving it to firebase firestore by using:
let database = Firestore.firestore()
database.collection("UserInfo").addDocument()
then after you save it to firestore you are trying to access it from real time database, not Firestore which is causing it to return nil:
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value) { (snapshot) in
So instead what you need to do is get it back from firestore by using this:
Firestore.firestore().collection("s").getDocuments { query, error in
for doc in query!.documents {
// Successfully retrieved data from firestore.
}
}
Note: You could also instead save it to the real time database instead of firestore, but it just depends which one will work better for your app. You need to pick either Firestore or the Database, you can't use both. Here is more info to help you decide which one is better. More Info

fetch the last document from Firestore collection

I have a tableViewController that fetch document from Firestore collection which called "paperHole" and i have refreshControl which is a UIrefreshControl that refresh the tableView but in this refreshControl action i want to fetch the last document only that recorded in the Firestore . what i mean is if the collection "paperHole" have 3 documents which is ( A, B, C ) and the last document recorded in this collection is C , i want to fetch the document C only .
i tried with limit(toLast: 1) but it didn't work for me
import UIKit
import FirebaseFirestore
import Firebase
import FirebaseAuth
import UserNotifications
class OrderTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet var order5: UITableView!
struct GlobalVariable{
static var myString = String()
}
var db: Firestore!
var street = [String]()
var firstName = [String]()
var lastName = [String]()
var blockNumber = [String]()
var phone = [String]()
var reciept = [String]()
var houseNumber = [String]()
var price = [String]()
var amount = [String]()
var block = [String]()
var Area = [String]()
var names = [String]()
var refreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refreshControl.attributedTitle = NSAttributedString(string: "")
refreshControl.addTarget(self, action: #selector(self.refresh(_:)), for: .valueChanged)
order5.addSubview(refreshControl)
order5.separatorStyle = .none
order5.dataSource = self
order5.delegate = self
db = Firestore.firestore()
}
#objc func refresh(_ sender: AnyObject) {
loadData1Refresh()
}
func loadData1Refresh() {
Firestore.firestore().collection("paperHole").limit(toLast: 1).getDocuments() {
(querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
var count = 0
for document in querySnapshot!.documents {
count += 1
print("\(document.documentID) => \(document.data())");
self.firstName.append(document.get("firstname") as? String ?? "")
self.lastName.append(document.get("lastname") as? String ?? "")
self.street.append(document.get("street") as? String ?? "")
self.blockNumber.append(document.get("blockNumber") as? String ?? "")
self.Area.append(document.get("area") as? String ?? "")
self.phone.append(document.get("phone") as? String ?? "")
self.reciept.append(document.get("reciept") as? String ?? "")
self.houseNumber.append(document.get("houseNumber") as? String ?? "")
self.price.append(document.get("total price") as? String ?? "")
self.amount.append(document.get("amount") as? String ?? "")
}
}
self.order5.reloadData()
}
}
I believe that using limit won't work unless you specify an order too.
Firstly, you'll need to attach a date to your paperHole object. As per the Firebase Docs:
Important: Unlike "push IDs" in the Firebase Realtime Database, Cloud Firestore auto-generated IDs do not provide any automatic ordering. If you want to be able to order your documents by creation date, you should store a timestamp as a field in the documents.
Then you can query your data using:
Firestore.firestore().collection("paperHole").order(by: "date", descending: true).limit(to: 1)

binary data not fetching in UIImageView when called

My swift code below is using a textfield to enter a number. When the app builds 2 images are saved to core data binary data image. There is a index connected to it to control the order of the way the images are saved. When the user enters 1 in the textfield the 1st image should appear when 2 is entered. A gif is below of want I want to achieve.
import UIKit
import CoreData
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var labelName : UILabel!
#IBOutlet var enterT : UITextField!
#IBOutlet var pic : UIImageView!
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var dx = [UIImage]()
var names = [String]()
override func viewDidLoad() {
super.viewDidLoad()
enterT.delegate = self
pic.backgroundColor = .cyan
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Users", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
let item2 = NSManagedObject(entity: entity, insertInto: managedContext)
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
let vex = UIImage(named: "on.jpg")?.pngData()
if let data = vex{
item.setValue(data, forKey: "image")
}
let vex2 = UIImage(named: "house.jpg")?.pngData()
if let data2 = vex2{
item2.setValue(data2, forKey: "image")
}
do {
let result = try? managedContext.fetch(fetch) as? [Users]
print("Queen",result?.count)
try? managedContext.save()
}
catch {
print("Could not save")
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = (textField.text as? NSString)?.replacingCharacters(in: range, with: string), let index = Int(text) else { //here....
// display an alert about invalid text
return true
}
save(at: index )
return true
}
func save(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
pic.image = UIImage(data: user.image ?? Data())
}
} catch {
print("Could not fetch \(error) ")
}
return
}
#IBAction func add(){
fetch()
}
func fetch()
{
for i in 0..<dx.count {
let newUser = Users(context: context)
newUser.image = dx[i].jpegData(compressionQuality: 1)
newUser.idx = Int32(i + 1)
}
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
return
}
}
You are mixing up fetching and saving
When you add items to the database create objects and save the context. Don't fetch.
When you load items from the database fetch the records. Don't save.
I don't know if shouldChangeCharactersIn works as expected. The other code is supposed to work.
And once again, on every application launch the (same) two items are added to the data base again.
Be aware of that. If the items exist delete or comment out the line populateData() in viewDidLoad.
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var labelName : UILabel!
#IBOutlet var enterT : UITextField!
#IBOutlet var pic : UIImageView!
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
enterT.delegate = self
pic.backgroundColor = .cyan
populateData()
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = (textField.text as? NSString)?.replacingCharacters(in: range, with: string), let index = Int(text) else { //here....
// display an alert about invalid text
return true
}
loadImage(at: index )
return true
}
func loadImage(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
pic.image = UIImage(data: user.image!)
} else {
pic.image = nil
}
} catch {
print("Could not fetch \(error) ")
}
}
#IBAction func add(){
// fetch()
}
func populateData()
{
let item = Users(context: context)
let vex = UIImage(named: "on.jpg")!.pngData()
item.image = vex
item.idx = 1
let item2 = Users(context: context)
let vex2 = UIImage(named: "house.jpg")!.pngData()
item2.image = vex2
item2.idx = 2
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
}
}

swift4 creating users info name, age and getting data back from fire base

I have created firebase all good with sign in and signup I can
store images as well but can't get images back that are stored in firebase and I want to create user profile to store name and age of user,
success with login, storing image with firebase and have created real time data base child such as image user name and age but cant use in my app, issue in creating user profile and issue with getting image back from firebase storage.
import UIKit
import FirebaseAuth
import Firebase
import FirebaseStorage
class ViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var ref : DatabaseReference?
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var myImage: UIImageView!
#IBOutlet weak var userName: UITextField!
#IBOutlet weak var ageTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// get image from firebase
// imagesFolder.
// let imageBack = Database.database().reference().child("images").child("user")
// self.myImage.image = UIImage(data: data!)
// creating dataBase
ref = Database.database().reference()
if Auth.auth().currentUser != nil {
ref?.child("images").child("username").setValue(["name":"first", "age":28])
}
}
#IBAction func loginButtonPressed(_ sender: UIButton) {
}
// signUp Button pressed
#IBAction func signUpButtonPressed(_ sender: UIButton) {
Auth.auth() .createUser(withEmail: emailTextField!.text!, password: passwordTextField!.text!) {(user,error)
in
if user != nil
{
self.performSegue(withIdentifier: "goToHome", sender: self)
print("SignUp Sucessfull")
}
else {
print("unSucessfull")
// uiAlert
let alert = UIAlertController(title:"wrong Information", message: nil, preferredStyle: .alert)
let okButton = UIAlertAction(title: "ok", style: .default, handler: nil)
alert.addAction(okButton)
self.present(alert,animated: true,completion: nil)
print("login Failed")
}
guard let userName = self.userName.text,!userName.isEmpty else {
print("Email is Empty");return
}
guard let userAge = self.ageTextField.text,!userAge.isEmpty else {
print("Age is required"); return
}
}
// upload image data to firebase
let imagesFolder = Storage.storage().reference().child("images")
if let image = myImage.image {
if let imageData = image.jpegData(compressionQuality: 0.75) {
imagesFolder.child("\(NSUUID().uuidString).jpg").putData(imageData, metadata: nil,completion: { (metadata,error) in
if let error = error {
// alert notification
}
// putData(_:metadata:completion:)
})
}
}
I have crazy comment please ignore that !
I have found the answer myself for future coders this can be a reference !
// user info stored
let userID = Auth.auth().currentUser?.uid
let userData = ["userName": userName,
"userAge ": userAge] as [String? : Any]
let ref = Database.database().reference()
ref.child("users/\(userID ?? "")").setValue(userData)
}
now to retrieve data create a struct and put the code in view did load
func fetchCurrentUserData() {
guard let currentUid = Auth.auth().currentUser?.uid else { return }
let userRef = Database.database().reference().child("users").child(currentUid)
print("userRef: \(userRef)")
userRef.observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
let uid = snapshot.key
let user = User(uid: uid, dictionary: dictionary)
self.user = user
print(snapshot.key)
}
}

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.