I'm creating an app that allows users to create sheet of notes.
In order to make this I've created a UICollectionViewController and each element is an object of the class Books.
Then I create an array that contains all this books.
My Question is: How can I memorize books, with their name, type..., in device's memory?
I try to use:
let booksDefault = UserDefaults.standard
if (booksDefault.value(forKey: "booksDefault") != nil) {
books = booksDefault.value(forKey: "booksDefault") as! [Books]
}
let booksDefault = UserDefaults.standard
booksDefault.setValue(books, forKey: "booksDefault")
booksDefault.synchronize()
but it doesn't work.
Thank you
Related
My swift code below saves 3 images. What I want to do is overwrite iamgedata2 is func press. Imagedata2 should be replaced with Gwen. So the order should be Gwen Gwen Gwen instead of Gwen gwen2 Gwen. I don't know what really to put in func press to achieve this goal.
import UIKit; import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
let gwen = UIImage(named: "blank")
let gwen2 = UIImage(named: "g.jpg")
if let imageData = gwen.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData)
}
if let imageData2 = gwen2.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData2)
}
if let imageData3 = gwen.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData3)
}
}
#objc func press(){
CoredataHandler.shareInstance.saveImage(data: 1)
return
}
}
class CoredataHandler : NSManagedObject {
static let shareInstance = CoredataHandler()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
func saveImage(data: Data) {
let imageInstance = Information(context: context)
imageInstance.pic = data
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
}
If you want a Core Data entity that can store more than one image, you have a few options:
Declare multiple image properties
Instead of just having a pic property, have more than one. As many as you like. Name them pic1, pic2, pic3, etc, or whatever seems best for your app. In code, read or write whichever makes sense at the time.
This is easy but not flexible, since your code can only save up to the number of attributes you declare in the model.
Use an array property with transformable
With a transformable attribute you can store any data that can be converted to a Data. In your case you'd do something like this:
Two things to notice: The type is transformable, and the custom class is [Data]. Xcode will generate code where the property type is [Data]?. You can save as many Data blobs as you want in it, representing however many images you want.
This is also easy but may use a lot of memory, because you can't access one image without loading all of them into memory at once. If you always load all of them anyway then it's no different. If you often load only one of them, this technique might use a lot more memory (e.g. 4 images would mean around 4x as much memory used).
Use a separate entity to hold the image and a to-many relationship
With this approach you'd create a new Core Data entity that only holds the image. Your existing entity would have a to-many relationship to this entity. You'd create as many image-only instances as you want, and the relationship would mean they were all available at any time.
You would probably want to make sure the to-many relationship is ordered, otherwise the images would be an unordered set that could be in any order.
This is a little more complex to write but it's flexible and doesn't have the potential memory problems of other approaches.
I have a list of countries and a field on them is favorite. If a user toggles the favorite button, that country's bool value of favorite is true. Elsewhere in my code, I use favorites to filter through all the countries and have a separate view that just shows the favorite countries.
#State var countries: [Country] = Bundle.main.decode("Countries.json")
var favorites : [Country] {
return countries.filter { $0.favorite }
}
I want to persist the countries so that I can reload the favorites view on subsequent app visits. Can I use #AppStorage for this or am I going about this the wrong way? CoredData seemed a bit like overkill when I was looking into it. I am new to SwiftUI coming to Javascript so apologies if this seems trivial.
In your case optimal will be to use UserDefaults
Use this part of code in func() or init()
For saving data in UserDefaults:
if let encoded = try? JSONEncoder().encode([Country]) {
UserDefaults.standard.set(encoded, forKey: "Countries")
}
For loading data from UserDefaults:
if let data = UserDefaults.standard.data(forKey: "Countries") {
if let decoded = try? JSONDecoder().decode([Country], from: data) { }
}
p/s
And I would like to recommend SwiftUI Tutorial from Apple if you are beginner
i'm creating my first app (and newbie in swift). When i login from Facebook, the name and email are saved in Firestore. I'm trying to set the name from facebook to a variable to use it in other places, but i can't assign the value, always shows "nil" in the console. Anyone can help me please?
I set the variable
var userN: String?
I get the data from Firestore
func readDatabase(){
let db = Firestore.firestore()
let docRef = db.collection("users").document("email")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
let data = document.data()
let userName = data!["name"]! as! String
print(userName)
let userEmail = data!["email"]! as! String
print(userEmail)
let containerController = ContainerController()
let containerController.userN = userName;
return
}
}
}
i want to assign userN = userName, to use it in other view
How can i do that? thanks
If you are using StoryBoards you can pass this through the segue function;
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourStoryBoardSegue" {
if let viewController = segue.destination as? ContainerController {
viewController.userN = userName
}
}
}
otherwise, best practice would be to use a delegate method.
Search stack overflow for best practices using delegates to pass data.
The question is extremely broad and without knowing details the only way to address it is with a general answer that specifically addresses how to read data from Firestore and save it in a variable to be used later.
Suppose your Firestore looks like this
root
users
uid_0
name: "users name"
uid_1
name: "another users name"
and when the app loads, we want to read the users name and store it in in a variable per your question:
a variable to use it in other places
Here's what that could look like
class ViewController: NSViewController {
var usersName = ""
override func viewDidLoad() {
super.viewDidLoad()
FirebaseApp.configure()
self.db = Firestore.firestore()
let settings = self.db.settings
self.db.settings = settings
self.readUserName()
}
func readUsersName() {
let users = self.db.collection("users")
let thisUser = users.document("uid_1")
thisUser.getDocument(completion: { documentSnapshot, error in
if let error = error {
print(error.localizedDescription)
return
}
let name = documentSnapshot?.get("name") as! String
self.usersName = name
})
}
The code sets up Firestore, reads the user name from the uid_1 document and stores it in a variable where it could be used later.
Suppose we want to let the user change their name. There's 100 ways to do it; passing data via a segue, use a delegate method or open a detail view controller and before it closes, have this master controller read the updated name from a textField and save the data. You could even pass the users uid and then in the detail viewcontroller read the document via that uid and then update it upon closing. However, all of those go beyond the scope of the question.
I'm saving data in one view with the following code:
let item1:String = textfield.text!
if TextField1.text != "" {
self.ref.child("userProfile").child((user!.uid)/value1Total").setValue(Double(item1)!)
}
What would be my code in a different view to set that saved value to a label?
You can try like below example:
let name = nameTextField.text
let user: NSDictionary = ["name":name!,"dob":dateOfBirthTimeInterval]
//add firebase child node
let profile = firebase.ref.childByAppendingPath(name!)
// Write data to Firebase
profile.setValue(user)
Have a look on it this link for more info
So iv using an NSTokenField to allow data entry, the TokenField will suggest thing when the user starts typing. I want it to suggest things that are already inside core data.
To do this i have this function being called when the cell moves to superview (This is all happening inside a custom table view cell)
var subjectInformation = [NSManagedObject]()
let appDel = NSApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "SubjectInformation")
do {
let results = try context.executeFetchRequest(fetchRequest)
subjectInformation = results as! [NSManagedObject]
} catch {
}
this returns an array of NSManagedObjects, now i want for every object in managed object get get the valueForKey("subjectName") as insert it into a array of string so that i can return that inside this token field Function
func tokenField(tokenField: NSTokenField, completionsForSubstring substring: String, indexOfToken tokenIndex: Int, indexOfSelectedItem selectedIndex: UnsafeMutablePointer<Int>) -> [AnyObject]? {
return subjectInformation //this is where is should return an array eg; ["English","Maths","Science"]
How would i do this? Thanks :)
If you properly subclassed your NSManagedObject you can use expressive Swift style filters and maps. You would cast your results array to [SubjectInformation] and
let subjectList = subjectInformation.map { $0.subjectName }
Try this:
(subjectInformation as! NSArray).valueForKeyPath("#unionOfObjects.subjectName")
This should return an array of the subjectNames of all the subjectInformation items.