I Have A UserDefault String Value That I Want To Convert To A Date In SwiftUI - date

I have created a class in SwiftUI that I use to save UserDefaults:
import Foundation
import SwiftUI
import Combine
class UserSettings: ObservableObject {
#Published var vin: String {
didSet {
UserDefaults.standard.set(vin, forKey: "VIN")
}
}
#Published var dateOfPurchase: String {
didSet {
UserDefaults.standard.set(dateOfPurchase, forKey: "Date of Purchase")
}
}
#Published var currentMiles: String {
didSet {
UserDefaults.standard.set(currentMiles, forKey: "Current Miles")
}
}
#Published var cell: String {
didSet {
UserDefaults.standard.set(cell, forKey: "Cell")
}
}
#Published var email: String {
didSet {
UserDefaults.standard.set(email, forKey: "Email")
}
}
#Published var tcIsOn: Bool {
didSet {
UserDefaults.standard.set(tcIsOn, forKey: "Toyota Care")
}
}
init() {
self.vin = (UserDefaults.standard.object(forKey: "VIN") ?? "") as! String
self.dateOfPurchase = (UserDefaults.standard.object(forKey: "Date of Purchase") ?? "") as! String
self.currentMiles = (UserDefaults.standard.object(forKey: "Current Miles") ?? "") as! String
self.cell = (UserDefaults.standard.object(forKey: "Cell") ?? "") as! String
self.email = (UserDefaults.standard.object(forKey: "Email") ?? "") as! String
self.tcIsOn = (UserDefaults.standard.object(forKey: "Toyota Care") ?? false) as! Bool
}
}
Basically what I want to do is pull my string value "dateOfPurchase" from UserDefaults convert it to a date format it "MM/dd/yyyy" and then display it in a Text() object. It would seem simple but SwiftUI is not cooperating. My other string values work fine but converting from string --> date is proving problematic. Any insights would be appreciated.

Related

problem with adding element to swift array

I am creating an application. I make a request to the firebase store, after that I add the result to the array, but in the end, when the array is displayed from viewDidLoad or other functions, I get an empty array. But if you make a conclusion immediately after the request, then everything is displayed correctly
`
import UIKit
import Firebase
import FirebaseStorage
import FirebaseFirestore
class CatalogVC: UIViewController {
struct Item: Codable {
var title: String
var price: Int
var description: String
var imageUrl: String
}
#Published var items: [Item] = []
let database = Firestore.firestore()
#IBOutlet weak var textViewCatalog: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let settings = FirestoreSettings()
Firestore.firestore().settings = settings
itemsList()
print(items)
showCatalogVC()
}
#IBAction func showCatalogTapped() {
}
private func showCatalogVC() {
print("SHOW CATALOG")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let dvc = storyboard.instantiateViewController(withIdentifier: "CatalogVC") as! CatalogVC
self.present(dvc, animated: true, completion: nil)
}
func itemsList(){
database.collection("catalog")
.getDocuments { (snapshot, error) in
self.items.removeAll()
if let snapshot {
for document in snapshot.documents{
let docData = document.data()
let title: String = docData["title"] as? String ?? ""
let imageUrl: String = docData["imageUrl"] as? String ?? ""
let description: String = docData["description"] as? String ?? ""
let price: Int = docData["price"] as? Int ?? 0
let item: Item = Item(title: title, price: price, description: description, imageUrl: imageUrl)
self.items.append(item)
}
}
}
}
}
`
I am creating an application. I make a request to the firebase store, after that I add the result to the array, but in the end, when the array is displayed from viewDidLoad or other functions, I get an empty array. But if you make a conclusion immediately after the request, then everything is displayed correctly
Getting data from Firebase is asynchronous process. So here you should make everything after loading data in closure database.collection("catalog").getDocuments {...}.
func itemsList(){
database.collection("catalog")
.getDocuments { (snapshot, error) in
self.items.removeAll()
if let snapshot {
for document in snapshot.documents{
let docData = document.data()
let title: String = docData["title"] as? String ?? ""
let imageUrl: String = docData["imageUrl"] as? String ?? ""
let description: String = docData["description"] as? String ?? ""
let price: Int = docData["price"] as? Int ?? 0
let item: Item = Item(title: title, price: price, description: description, imageUrl: imageUrl)
self.items.append(item)
}
}
print(self.items) //print items to see them
//here use items data
}
}

swift saving an array set <Int> to usderdefaults

I'm trying to save an array set to user defaults as part of a class, but I get an error whenever I add to the array in a view. Everything else works when I change the variable (i.e., saved to userdefaults and available in the changed state when I restart the app). The issue seems to be in writing the data to the UserDefaults rather than initializing it or reading it. Thanks!
Thread 1: "Attempt to insert non-property list object {(\n 20\n)} for key savedFavs"
Here's the code
import Foundation
import Combine
import SwiftUI
class Preferences: ObservableObject {
#Published var chosenVersion: Int {
didSet {
UserDefaults.standard.set(self.chosenVersion, forKey: "savedVersion")
}
}
#Published var isPsalmsExpanded: Bool {
didSet {
UserDefaults.standard.set(self.isPsalmsExpanded, forKey: "savedExpanded")
}
}
#Published var showMT: Bool {
didSet {
UserDefaults.standard.set(self.showMT, forKey: "savedMT")
}
}
#Published var fontSize: Int {
didSet {
UserDefaults.standard.set(self.fontSize, forKey: "savedSize")
}
}
#Published var scrollPosition: Int = 0
#Published var preferredColor: ColorScheme {
didSet {
UserDefaults.standard.set(self.preferredColor, forKey: "savedColor")
}
}
#Published var favPsalms: Set<Int> {
didSet {
UserDefaults.standard.set (self.favPsalms, forKey: "savedFavs")
}
}
init() {
self.chosenVersion = UserDefaults.standard.object(forKey: "savedVersion") as? Int ?? 0
self.isPsalmsExpanded = UserDefaults.standard.object(forKey: "savedExpanded") as? Bool ?? false
self.showMT = UserDefaults.standard.object(forKey: "savedMT") as? Bool ?? false
self.fontSize = UserDefaults.standard.object(forKey: "savedSize") as? Int ?? 20
self.preferredColor = UserDefaults.standard.object(forKey: "savedColor") as? ColorScheme ?? .light
self.favPsalms = UserDefaults.standard.object(forKey: "savedFavs") as? Set<Int> ?? Set<Int>()
}
}

Firestore responding with "cannot find 'cards' in scope"

I followed this tutorial to get data from firestore and changed what i needed to correspond to my model but it keeps responding with "cannot find 'cards' in scope" and I'm not sure what i did wrong. (i think i got the mvvm labels right)
VIEW
import SwiftUI
struct TestingView: View {
#ObservedObject private var viewModel = CardViewModel()
var body: some View {
List(viewModel.cards) {
Text(cards.name)
}
.onAppear() {
self.viewModel.fetchData()
}
}
}
VIEW MODEL
import Foundation
import Firebase
class CardViewModel: ObservableObject {
#Published var cards = [Cards]()
private var db = Firestore.firestore()
func fetchData() {
db.collection("cards").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.cards = documents.map { queryDocumentSnapshot -> Cards in
let data = queryDocumentSnapshot.data()
let name = data["name"] as? String ?? ""
let pronoun = data["pronoun"] as? String ?? ""
let bio = data["bio"] as? String ?? ""
let profileURLString = data["profileURLString"] as? String ?? ""
let gradiantColor1 = data["gradiantColor1"] as? UInt ?? 0
let gradiantColor2 = data["gradiantColor2"] as? UInt ?? 0
let gradiantColor3 = data["gradiantColor3"] as? UInt ?? 0
return Cards(name: name, pronoun: pronoun, bio: bio, profileURLString: profileURLString, gradiantColor1: gradiantColor1, gradiantColor2: gradiantColor2, gradiantColor3: gradiantColor3)
}
}
}
}
MODEL
import Foundation
struct Cards: Identifiable {
var id = UUID().uuidString
var name: String
var pronoun: String
var bio: String
var profileURLString: String
var gradiantColor1: UInt
var gradiantColor2: UInt
var gradiantColor3: UInt
var profileURL: URL {
return URL(string: profileURLString)!
}
}
List will provide an element to its trailing closure -- see card in in my code. Then, you can access that specific card in your Text element.
var body: some View {
List(viewModel.cards) { card in //<-- Here
Text(card.name) //<-- Here
}
.onAppear() {
self.viewModel.fetchData()
}
}
}
I'd suggest that you might want to rename the struct Cards to struct Card since it is one card. Then, your array would be #Published var cards = [Card]() -- ie an array of Cards. From a naming perspective, this would make a lot more sense.

Can't add data fetched from Firebase to new Array

I'm am fetching data from firebase from 3 different collections. Once I have the data fetched I would like to append the data from the 3 functions to 1 new array so I have all the data stored one place. But once I append it comes out empty like the fetch functions didn't work. I've tested and debugged and the data is there but I can't seem to add the fetched data to a new Array.
Model
import Foundation
import SwiftUI
struct GameModel: Identifiable {
var id = UUID()
var title: String
var descriptionMenu: String
var imageNameMenu: String
}
Fetch Data Class
import Foundation
import SwiftUI
import Firebase
class SearchController: ObservableObject {
#Published var allGames = [GameModel]()
#Published var cardsMenu = [GameModel]()
#Published var diceMenu = [GameModel]()
#Published var miscellaneuosMenu = [GameModel]()
private var db = Firestore.firestore()
func fetchCardGamesData() {...}
func fetchDiceGamesData() {...}
func fetchMiscGamesData() {...}
func combineGames() {
for i in cardsMenu {
allGames.append(i)
}
for n in diceMenu {
allGames.append(n)
}
for x in miscellaneuosMenu {
allGames.append(x)
}
}
}
Fetch data Functions
func fetchCardGamesData() {
db.collection("cardsMenu").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.cardsMenu = documents.map { (queryDocumentSnapshot) -> GameModel in
let data = queryDocumentSnapshot.data()
let title = data["title"] as? String ?? ""
let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of: "\\n", with: "\n")
let imageNameMenu = data["imageNameMenu"] as? String ?? ""
let allGameInfo = GameModel(title: title, descriptionMenu: descriptionMenu, imageNameMenu: imageNameMenu)
return allGameInfo
}
}
}
func fetchDiceGamesData() {
db.collection("diceMenu").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.diceMenu = documents.map { (queryDocumentSnapshot) -> GameModel in
let data = queryDocumentSnapshot.data()
let title = data["title"] as? String ?? ""
let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of: "\\n", with: "\n")
let imageNameMenu = data["imageNameMenu"] as? String ?? ""
let allGameInfo = GameModel(title: title, descriptionMenu: descriptionMenu, imageNameMenu: imageNameMenu)
return allGameInfo
}
}
}
func fetchMiscGamesData() {
db.collection("miscellaneuosMenu").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.miscellaneuosMenu = documents.map { (queryDocumentSnapshot) -> GameModel in
let data = queryDocumentSnapshot.data()
let title = data["title"] as? String ?? ""
let descriptionMenuRecieved = data["descriptionMenu"] as? String ?? ""
let descriptionMenu = descriptionMenuRecieved.replacingOccurrences(of: "\\n", with: "\n")
let imageNameMenu = data["imageNameMenu"] as? String ?? ""
let miscellaneousGames = GameModel(title: title, descriptionMenu: descriptionMenu, imageNameMenu: imageNameMenu)
return miscellaneousGames
}
}
}
View
import SwiftUI
import Foundation
struct SearchView: View {
#ObservedObject var allGames = SearchController()
var body: some View {
NavigationView{
ZStack(alignment: .top) {
GeometryReader{_ in
//Text("Home")
}
.background(Color("Color").edgesIgnoringSafeArea(.all))
SearchBar(data: self.$allGames.allGames)
.padding(.top)
}
.navigationBarTitle("Search")
.padding(.top, -20)
.onAppear(){
self.allGames.fetchCardGamesData()
self.allGames.fetchDiceGamesData()
self.allGames.fetchMiscGamesData()
self.allGames.combineGames()
}
}
.navigationViewStyle(StackNavigationViewStyle())
.listStyle(PlainListStyle())
}
}
SearchBar
struct SearchBar: View {
#State var txt = ""
#Binding var data: [GameModel]
var body: some View {
VStack(spacing: 0){
HStack{
TextField("Search", text: self.$txt)
if self.txt != "" {
Button(action: {
self.txt = ""
}, label: {
Image(systemName: "xmark.circle.fill")
})
.foregroundColor(.gray)
}
}.padding()
if self.txt != ""{
if self.data.filter({$0.title.lowercased().contains(self.txt.lowercased())}).count == 0 {
Text("No Results Found")
.foregroundColor(Color.black.opacity(0.5))
.padding()
}
else {
List(self.data.filter{$0.title.lowercased().contains(self.txt.lowercased())}){
i in
NavigationLink(destination: i.view.navigationBarTitleDisplayMode(.inline).onAppear(){
// Clear searchfield when return
txt = ""
}) {
Text(i.title)
}
}
.frame(height: UIScreen.main.bounds.height / 3)
.padding(.trailing)
}
}
}
.background(Color.white)
.cornerRadius(10)
.padding()
}
}
Hope you guys can help me.
All of your fetchCardGamesData, fetchDiceGamesData, and fetchMiscGamesData functions have asynchronous requests in them. That means that when you call combineGames, none of them have completed, so you're just appending empty arrays.
In your situation, the easiest would probably be to make allGames a computed property. Then, whenever one of the other #Published properties updates after their fetch methods, the computed property will be re-computed and represented in your SearchBar:
class SearchController: ObservableObject {
#Published var cardsMenu = [GameModel]()
#Published var diceMenu = [GameModel]()
#Published var miscellaneuosMenu = [GameModel]()
var allGames: [GameModel] {
cardsMenu + diceMenu + miscellaneuosMenu
}
}
Note there's no longer a combineGames function, so you won't call that anymore.

Back4app - Swift - Cast PFObject to Class

I am trying to cast a PFObject to a custom class in Swift and I read a lot of post about it and in all of then I need to inherit my class from PFObject. The problem is that my class is already inherited from NSObject and there is a conflict between then.
Is there another way to cast a PFObject to a custom class?
Usuario.swift
class Usuario: NSObject, NSCoding {
//MARK: Propriedades
var nome: String?
var foto: String?
var dataNascimento: Date?
var numeroTelefone: String?
var pais: PaisCodigo?
var telefoneE164: String?
var objectId: String?
var created: Date?
var updated: Date?
override init() {}
required init(coder aDecoder: NSCoder) {
nome = aDecoder.decodeObject(forKey: "nome") as? String
foto = aDecoder.decodeObject(forKey: "foto") as? String
dataNascimento = aDecoder.decodeObject(forKey: "dataNascimento") as? Date
numeroTelefone = aDecoder.decodeObject(forKey: "numeroTelefone") as? String
pais = aDecoder.decodeObject(forKey: "pais") as? PaisCodigo
telefoneE164 = aDecoder.decodeObject(forKey: "telefoneE164") as? String
objectId = aDecoder.decodeObject(forKey: "objectId") as? String
created = aDecoder.decodeObject(forKey: "created") as? Date
updated = aDecoder.decodeObject(forKey: "updated") as? Date
}
func encode(with aCoder: NSCoder) {
if let nomeUsuario = nome {
aCoder.encode(nomeUsuario, forKey: "nome")
}
if let fotoUsuario = foto {
aCoder.encode(fotoUsuario, forKey: "foto")
}
if let dataNascimentoUsuario = dataNascimento {
aCoder.encode(dataNascimentoUsuario, forKey: "dataNascimento")
}
if let numeroTelefoneUsuario = numeroTelefone {
aCoder.encode(numeroTelefoneUsuario, forKey: "numeroTelefone")
}
if let paisUsuario = pais {
aCoder.encode(paisUsuario, forKey: "pais")
}
if let telefoneE164Usuario = telefoneE164 {
aCoder.encode(telefoneE164Usuario, forKey: "telefoneE164")
}
if let objectIdUsuario = objectId {
aCoder.encode(objectIdUsuario, forKey: "objectId")
}
if let createdUsuario = created {
aCoder.encode(createdUsuario, forKey: "created")
}
if let updatedUsuario = updated {
aCoder.encode(updatedUsuario, forKey: "updated")
}
}
}
The Parse result using an objectId returns me this result:
<Usuario: 0x6080000abb20, objectId: 7NwpmD81w3, localId: (null)> {
nome = "Pablo Cavalcante";
numeroTelefone = 67992497386;
pais = "<PaisCodigo: 0x6080000abb80, objectId: rA5wdIWEFt, localId: (null)>";
telefoneE164 = "+5567992497386"; }
So it returns an Usuario object and I need to cast it.
You can use PFSubclassing. I see that you're declaring a user class so you could just subclass PFUser and then write something like this:
class User: PFUser, PFSubclassing {
//MARK: Propriedades
dynamic var nome: String?
dynamic var foto: String?
dynamic var dataNascimento: Date?
dynamic var numeroTelefone: String?
dynamic var pais: PaisCodigo?
dynamic var telefoneE164: String?
dynamic var objectId: String?
dynamic var created: Date?
dynamic var updated: Date?
}
Of course if you're using the init(with:) and encode(with:) you have to implement it...