Using a boolean attribute in Core Data Swift - swift

I am new to core Data and I want to create a boolean atribute to my App. My entity is RemoveAds and the atribute is isAdRemoved. I want it to inicialize it to false if the ad was not removed yet, but when he press a button to remove the ad it turns into true, any suggestions?
Obs: I have all my IAP setup, this is not the issue here
Update 1:
func removeallAds() {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
let entity = NSEntityDescription.entityForName("RemoveAds", inManagedObjectContext: context)
let newObject = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: context) as RemoveAds
newObject.isAdRemoved = false
}

When you add a new object to CoreData, then you also initialize the attributes, e.g. to set your attribute default-wise to false use:
let entity = NSEntityDescription.entityForName("RemoveAds", inManagedObjectContext: managedContext)
let newObject = NSManagedObject(entity: entity, insertIntoManagedObjectContext:managedContext)
newObject.setValue(false, forKey: "isAdRemoved")
Once you received a button press, search for the corresponding object and set its property to true, again with setValue.
There is also a some tutorials for CoreData and Swift e.g. Your First Core Data App Using Swift.

Are you just trying to save a global app preference? If so, NSUserDefaults is likely a far better choice than Core Data.
http://ios-blog.co.uk/tutorials/quick-tips/storing-data-with-nsuserdefaults/ https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html

Related

Updated core data model without new version, how to fix?

I was working on an app update and I added and deleted some attributes and entities to my data model without creating a new version of it. It was my first app and unfortunately I was not using any version control system neither.
I have tried to delete the old sqlite file and recreate a new one when user updated the app but it crashes immediately after launch because one of the new attributes returns nil which I added recently.
I have a sign up screen so I thought I could show that screen again when app updated and fill my model with new data but that doesnt work either. I am compeletely lost as a beginner.
Scene Delegate
if !UserDefaults.standard.bool(forKey: K.DefaultKey.firstLaunch) {
UserDefaults.standard.set(true, forKey: K.DefaultKey.firstLaunch)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "onboard")
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
My code to delete and rebuild
class CoreData {
static let datamodelName = "DataModel"
static let storeType = "sqlite"
static let persistentContainer = NSPersistentContainer(name: datamodelName)
private static let url: URL = {
let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")
assert(FileManager.default.fileExists(atPath: url.path))
return url
}()
static func deleteAndRebuild() {
try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)
persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
guard let error = error else {
return
}
fatalError(error.localizedDescription)
})
}
}
Appdelegate
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
CoreDataContext.deleteAndRebuild()
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
Edit: I found hash codes of the old model via momd file. Can I use these hash codes to recreate old data model?
If possible, the best way to fix this would be to undo the model changes, so that it would be possible to load the current data. Then make the changes again properly so that migration could happen. You'd do something like
Start using source control.
Undo the recent changes (I know you don't have version control but you probably know what they were).
Verify step 1 by running the app using only that version of the model and making sure it loads data without crashing.
Create a new model version, make it the current version, and make your changes there. Core Data will then try to migrate the data to the new model.
[Update] The reason you're still getting a crash with your delete-and-rebuild code is that you're still calling fatalError after deleting and rebuilding the persistent store. If you've successfully recovered, you shouldn't also call fatalError, since its whole purpose is to crash the app. I don't know what you mean about one of the new attributes returning nil. That's expected of a new attribute, because since it's new, there's no data for it.

How to archive data of UICollectionView elements

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

Calling a Core Data attribute through a relationship

I have two Entities as depicted in the image below:
Food and Restaurant.
I know the naming is a bit off for now, but basically, I'm building up a list of Food items. A user will add in a new entry with the name of the food and the name of the restaurant. I'm at the very early stages of development.
So in the AddViewController, and in the save method, I have:
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
foodEntry.nameOfFood = foodNameTextField.text
foodEntry.restaurantName?.nameOfRestaurant = restaurantNameTextField.text
With a variable declared:
var foodEntry:FoodManagedObject!
In the TimelineView, using NSFetchedResultsController, I'm fetching for the FoodManagedObject and able to display the name of the food in the label. However, the name of the restaurant doesn't display.
So, I'm fetching appropriately:
let fetchRequest: NSFetchRequest<FoodManagedObject> = FoodManagedObject.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "nameOfFood", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
if let fetchedObjects = fetchedResultsController.fetchedObjects {
foods = fetchedObjects
}
} catch {
print(error)
}
}
and in the cellForRow:
cell.foodNameLabel.text = foods[indexPath.row].nameOfFood
cell.restaurantLabel.text = foods[indexPath.row].restaurantName?.nameOfRestaurant
I get no errors, but the name of the restaurant never displays.
Foods is:
var foods:[FoodManagedObject] = []
So I've tried adding in an attribute called theRestaurant into the Food Entity and that works, but calling through a relationship never seems to work.
Am I missing something obvious here?
You're creating relations between the objects, not of their values
It means, that you must assign already existing restaurant entity object or create the new one when you're saving the new food object.
You can't just assign object values without an initialisation of the restaurant object.
E.g.
foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
foodEntry.nameOfFood = foodNameTextField.text
// Here you must to load existing Restaurant entity object from database or create the new one
let restaurant = RestaurantManagedObject(context: appDelegate.persistentContainer.viewContext)
restaurant.nameOfRestaurant = restaurantNameTextField.text
foodEntry.restaurantName = restaurant // Object instead of value
Or if you already have some list of restaurants, than just add the new food object to one of them

core data simple fetch request template in swift

Hi guys I fetched the data from core data using fetch request by programmatically ? my question is how to fetch data by using
fetchRequestTemplateForName ?
What you need to do is declare both managedObjectContext and managedObjectModel :
let context: NSManagedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let model: NSManagedObjectModel = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectModel
Then you can simply use fetch request template that you created. If template name is "olderThen35" code looks like this:
let request = model.fetchRequestTemplateForName("olderThen35")!

Request just one attribute of a entity

So I am using one core data file with a single one entity named BookArray, inside that entity I have four different attributes, what I want to do is to request just one of those attributes from the entity not all. Is it possible?
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "BookArray")
request.returnsObjectsAsFaults = false
bookArray = context.executeFetchRequest(request, error: nil)!
Suppose I have an attribute called sciFi and another named drama, how would I request just the drama attribute?
You can, by adding:
request.propertiesToFetch = ["drama"]
request.resultType = .DictionaryResultType
but, unless your other properties are big, it's unlikely to be worthwhile: your bookArray will then contain an array of dictionaries, from which you will need to unpack the relevant values: you might just as well do that directly from the array of NSManagedObjects returned by a normal fetch.