I'm trying to save an object to Core Data which is fetched from Parse, but i'd like only those which doesn't contain a name which is already in database:
func fetchFromParse() {
let entity = NSEntityDescription.entityForName("Medicine", inManagedObjectContext: context)
let query = PFQuery(className: "Medicine")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
for object in objects! {
let medicine = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.context)
if let name = object["medicineName"] as? String,
amount = object["amountQuantity"] as? String {
let predicate = NSPredicate(format: "name != %#", name)
self.fetchRequest.predicate = predicate
do{
let fetchedEntities = try self.context.executeFetchRequest(self.fetchRequest) as! [Medicine]
//save to Core Data
medicine.setValue(name, forKey: "name")
medicine.setValue(amount, forKey: "amount")
} catch let error as NSError{
print(error)
}
do {
try self.context.save()
self.tableView.reloadData()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
}
}
}
}
Fetch data from Core Data
func fetchFromCoreData() {
do {
let results = try context.executeFetchRequest(fetchRequest)
medicines = results as! [Medicine]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
i put the in viewWillAppear:
if Reachability.isConnectedToNetwork() {
//fetching data from Parse
fetchFromParse()
fetchFromCoreData()
tableView.reloadData()
} else {
//fetching data from Core data
fetchFromCoreData()
logOutButton.enabled = false
}
But it doesn't work. Any suggestions how to repair it ?
You kind of have everything, just not hooked up. You shouldn't be instantiating and inserting the new object until after you've executed and checked the fetch. You currently execute the fetch but don't check to see if there is a duplicate. Both of these issues need to be resolved, something along the lines of:
let entity = NSEntityDescription.entityForName("Medicine", inManagedObjectContext: context)
let query = PFQuery(className: "Medicine")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
for object in objects! {
if let name = object["medicineName"] as? String,
amount = object["amountQuantity"] as? String {
let predicate = NSPredicate(format: "name = %#", name)
self.fetchRequest.predicate = predicate
do{
let fetchedEntities = try self.context.executeFetchRequest(self.fetchRequest) as! [Medicine]
//save to Core Data
if fetchedEntities.count <= 0 {
let medicine = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.context)
medicine.setValue(name, forKey: "name")
medicine.setValue(amount, forKey: "amount")
}
} catch let error as NSError{
print(error)
}
}
}
do {
try self.context.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
}
Related
I am saving different activities to Core Data. While the app is working i can easily retrieve this data. But after the app I closed the data is gone even if even after I explicitly save it using context.save(). Any ideas why this happens?
private func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
func retrieveTestEntity() -> TestEntity? {
let managedContext = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "TestEntity")
do {
let result = try managedContext.fetch(fetchRequest) as! [TestEntity]
if result.count > 0 {
// Assuming there will only ever be one Entity in the app.
return result[0]
} else {
return nil
}
} catch let error as NSError {
print("Retrieving user failed. \(error): \(error.userInfo)")
return nil
}
}
func saveActivity(_ activity: Activity) {
let managedContext = getContext()
guard let testEntity = retrieveTestEntity() else { return }
testEntity.activity.append(activity)
do {
print("Saving session...")
try managedContext.save()
} catch let error as NSError {
print("Failed to save session data! \(error): \(error.userInfo)")
}
}
I want to fetch data from Core data and look for duplicats and then only save the data then there is no duplicate of the movieid.
Maybe some one can help me ..
How can I compare the result with the movieid string ?
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "MovieData")
//request.predicate = NSPredicate(format: "movieid = %#", movieID)
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "movieid") as! String)
}
} catch {
print("Failed")
}
Almost. Apply the predicate to get only the record with the specific movieID. However it assumes that movieID is an object (NSNumber), if it's an scalar Int you have to use %ld as placeholder.
If the fetch returns an empty array there is no duplicate and you can insert a new object
let request = NSFetchRequest<NSManagedObject>(entityName: "MovieData")
request.predicate = NSPredicate(format: "movieid = %#", movieID)
do {
let result = try context.fetch(request)
if result.isEmpty {
let newMovie = NSEntityDescription.insertNewObject(forEntityName: "MovieData", into: context) as! MovieData
newMovie.movieid = movieID
try context.save()
}
} catch {
print(error)
}
While saving in core data you need to create predicate and in there you need to check if there are values already saved with same "movieid" then it has to be updated , this way you won't have duplicate data . Please refer the method and try using the same for saving the values in DB . This way duplicate values won't be saved in DB
class func insertupdaterecord (movieID:String, context: NSManagedObjectContext)
{
let entityDescription = NSEntityDescription.entity(forEntityName: "movie", in: context)
let pred = NSPredicate(format: "movieid = %#", movieID)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "movie")
fetchRequest.entity = entityDescription
fetchRequest.predicate = pred
let result = try! (context.fetch(fetchRequest) as NSArray).lastObject
let updateInsertInfo : movie
if result != nil
{
updateInsertInfo = result as! movie
}
else
{
print("Record not found!")
}
do
{
try context.save()
}
catch let error as NSError
{
print("Error while saving \(error) in database.")
}
}
Create a cache for movieid values to check for duplicates and loop through the fetched result and delete any objects with a movieid already in the cache and then save once the loop is done.
var selection: [String] = []
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "MovieData")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
guard let movieId = data.value(forKey: "movieid") as? String else {
context.delete(data) // or however you want to handle this situation
continue
}
if selection.contains(movieId) {
context.delete(data)
} else {
selection.append(movieId)
}
}
try context.save()
} catch {
print("Failed")
}
I am trying to make a simple app to store and retrieve User data.
Have a RegisterViewController.swift with fields (name,loginUsername,loginPassword,photo) which Users enter to register.
I have a User.swift class to save this information in an object
Using CoreData, I have setup "Users" entity with the 4 fields as attributes.
I have referred the following links to save and retrieve data to the Users table.
https://medium.com/xcblog/core-data-with-swift-4-for-beginners-1fc067cca707.
https://www.bobthedeveloper.io/blog/beginner-guide-to-core-data-in-swift
However, I do not see any data being saved or retrieved when I debug. Neither do I see any exceptions.
Following is the snippet of code
let name = self.name.text;
let loginUsername = self.loginUsername.text;
let loginPassword = self.loginPassword.text;
let photo = self.photo.image;
print("Setting user data in the User object");
user = User(name: name!, loginUsername: loginUsername!, loginPassword: loginPassword!, photo: photo)!;
print("store data in DB")
//Setup delegate and context
let appDelegate = UIApplication.shared.delegate as! AppDelegate;
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Users", in: context);
let newUser = NSManagedObject(entity: entity!, insertInto: context)
//Set values for the attributes
newUser.setValue(name, forKey: "name")
newUser.setValue(loginUsername, forKey: "loginUsername")
newUser.setValue(loginPassword, forKey: "loginPassword")
//TODO: store the photo
//Save data
do {
print("Trying to same")
try context.save()
} catch {
print("Failed to save user")
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
//Method 1: to get Users after saving
do {
usersSaved = try context.fetch(Users.fetchRequest())
} catch {
print("Failed to fetch users")
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
//Method 2: to get Users after saving
var usersSaved: [Users] = []
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users");
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
print("Trying to fetch")
for data in result as! [NSManagedObject] {
print(data.value(forKey: "name") as! String)
}
} catch {
print("Failed")
}
This is my User.swift class
class User {
//MARK: Properties
var name: String;
var loginUsername: String;
var loginPassword: String;
var photo: UIImage? = nil;
//MARK: Initialization
init?(name: String, loginUsername: String, loginPassword: String, photo: UIImage?) {
//Initialization should fail if there is no name or username or password
if (name.isEmpty || loginUsername.isEmpty || loginPassword.isEmpty) {
return nil;
}
//Initialize stored properties
self.name = name;
self.loginUsername = loginUsername;
self.loginPassword = loginPassword;
self.photo = photo;
}
}
I have looked online for answers but was unable to figure it out. Any pointers or suggestions would really help me progress..
I am answering my own question for those who might face this issue. Thank you #Paulw11 for the suggestions. Xcode acts weird and I had to do Project -> Clean multiple times and delete DerivedData folder before the CoreData entities got resolved.
This is what I did
func storeUserData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate;
let context = appDelegate.persistentContainer.viewContext
//store data
let newUser = Users(context: context);
newUser.name = self.name.text;
newUser.loginUsername = self.loginUsername.text;
newUser.loginPassword = self.loginPassword.text;
appDelegate.saveContext();
//retrieve data
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users");
request.returnsObjectsAsFaults = false
do {
print("Fetching from DB")
let result = try context.fetch(request)
//printing data
for data in result as! [NSManagedObject] {
print(data.value(forKey: "name") as! String)
print(data.value(forKey: "loginUsername") as! String)
print(data.value(forKey: "loginPassword") as! String)
}
} catch {
print("Failed to fetch")
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
This is how I save data to core, now I want to delete specific object from whole data. How can I do that?
This is how I save data:
func saveProductDetails(product : Product) {
// set user_id
product.user_id = UserDefaults.sharedInstace.getCustomerId()
//save data locally for the time been
let entity = NSEntityDescription.entityForName("Product", inManagedObjectContext: self.writeContext)
let category = NSEntityDescription.entityForName("Category", inManagedObjectContext: self.writeContext)
let brand = NSEntityDescription.entityForName("Brand", inManagedObjectContext: self.writeContext)
var entityProduct = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:self.writeContext)
var entityCategory = NSManagedObject(entity: category!, insertIntoManagedObjectContext:self.writeContext)
var entityBrand = NSManagedObject(entity: brand!,insertIntoManagedObjectContext: self.writeContext)
entityProduct = product.settingManagedObject(entityProduct)
entityProduct.setValue(String(Utill.sharedInstace.getTimeStamp()), forKey: "time_stamp")
entityProduct.setValue(Constant.Status.STATUS_NOT_VERIFIED, forKey: "status")
if product.categoryObject != nil{
product.categoryObject.user_id = UserDefaults.sharedInstace.getCustomerId();
entityCategory = product.categoryObject.settingManagedObject(entityCategory)
}
if product.brandObject != nil{
product.brandObject.user_id = UserDefaults.sharedInstace.getCustomerId();
entityBrand = product.brandObject.settingManagedObject(entityBrand)
}
entityProduct.setValue(entityCategory, forKey:"category")
entityProduct.setValue(entityBrand, forKey: "brand")
writeContext.performBlock {
do {
try self.writeContext.save()
self.managedContext.performBlock({
do{
try self.managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
})
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
return
}
}
}
This Product object has relationship to two others and I want to delete only specific object, not all. That means delete (which the product.purchase_id == "selected_purchse_id"), in UITableView.
How to do that?
Check this code for swift 3 core data operations
import CoreData
class CoreDataOperations: NSObject {
// MARK: Save data
func saveData() -> Void {
let managedObjectContext = getContext()
let personData = NSEntityDescription.insertNewObject(forEntityName: "Person", into: managedObjectContext) as! Person
personData.name = "Raj"
personData.city = "AnyXYZ"
do {
try managedObjectContext.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
// MARK: Fetching Data
func fetchData() -> Void {
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
do {
let fetchedPerson = try moc.fetch(fetchRequest) as! [Person]
print(fetchedPerson.count)
for object in fetchedPerson {
print(object.name!)
}
} catch {
fatalError("Failed to fetch employees: \(error)")
}
}
// MARK: Delete Data Records
func deleteRecords() -> Void {
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Person]
for object in resultData {
moc.delete(object)
}
do {
try moc.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
// MARK: Update Data
func updateRecords() -> Void {
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Person]
for object in resultData {
object.name! = "\(object.name!) Joshi"
print(object.name!)
}
do{
try moc.save()
print("saved")
}catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
// MARK: Get Context
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
}
You can get more from https://github.com/rajkumar24u/CoreDataOperations
this is going to be a really noob question but I'm trying to get my app to download data from CloudKit and then save it to CoreData.
When I run this type of code, I get the following error. I'm really noob at CoreData, so this has been hard for me to understand. I think it has something to do with the way I'm dispatching the requests, but I'm not sure how I'm supposed to fix it. The error I get is:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'recordChangeSnapshot:forObjectID:: global ID may not be temporary when recording
'
Anyone have any ideas?
import UIKit
import CloudKit
import CoreData
class Start: UIViewController {
var classroomEN: String?
var classroomTC: String?
var classroomSC: String?
var videos = [NSManagedObject]()
override func viewDidLoad() {
fetchData()
fetchDataTC()
}
func fetchData() {
//added to fetch data from CloudKit
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let queryEN = CKQuery(recordType: "ClassroomFAQEN", predicate: predicate)
let queryTC = CKQuery(recordType: "ClassroomFAQTC", predicate: predicate)
queryEN.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
queryTC.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
publicData.performQuery(queryEN, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for entry in results! {
let newFAQ = classFAQ()
newFAQ.title = entry["Title"] as! String
newFAQ.content = entry["Content"] as! String
if entry["Picture"] != nil {
print("There is no picture")
newFAQ.picture = entry["Picture"] as! String
}
if entry["Video"] != nil {
print("There is no video")
newFAQ.video = entry["Video"] as! String
}
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("ClassroomFAQEN", inManagedObjectContext:managedContext)
let video = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
video.setValue(newFAQ.title, forKey: "title")
video.setValue(newFAQ.content, forKey: "content")
video.setValue(newFAQ.picture, forKey: "picture")
video.setValue(newFAQ.video, forKey: "video")
do {
try video.managedObjectContext!.save()
self.videos.append(video)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("Reloading data in tableView")
self.fetchDataTC()
})
}
}
else {
print(error)
}
}
}
func fetchDataTC() {
//added to fetch data from CloudKit
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let queryEN = CKQuery(recordType: "ClassroomFAQEN", predicate: predicate)
let queryTC = CKQuery(recordType: "ClassroomFAQTC", predicate: predicate)
queryEN.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
queryTC.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
publicData.performQuery(queryTC, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for entry in results! {
let newFAQ = classFAQ()
newFAQ.title = entry["Title"] as! String
newFAQ.content = entry["Content"] as! String
if entry["Picture"] != nil {
print("There is no picture")
newFAQ.picture = entry["Picture"] as! String
}
if entry["Video"] != nil {
print("There is no video")
newFAQ.video = entry["Video"] as! String
}
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("ClassroomFAQTC", inManagedObjectContext:managedContext)
let video = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
video.setValue(newFAQ.title, forKey: "title")
video.setValue(newFAQ.content, forKey: "content")
video.setValue(newFAQ.picture, forKey: "picture")
video.setValue(newFAQ.video, forKey: "video")
do {
try video.managedObjectContext!.save()
self.videos.append(video)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("Reloading data in tableView")
})
}
}
else {
print(error)
}
}
}
You can use isMainThread to determine if you're on a background thread.. or you can directly write the code like this, which will always ensure it's in main thread:-
dispatch_async(dispatch_get_main_queue(), { () -> Void in
do {
try video.managedObjectContext!.save()
self.videos.append(video)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
})