I'm building an app that stores locations in core data when the server connection is no longer available, then pushes these locations to the server when a connection is restored.
After fetching and printing these fetched objects from core data, I get tons of faults initially. I understand faults and what they represent, but shouldn't the number of faults be the same number of objects? The number of faults heavily outnumbers the number of objects (I can print out a 100+ faults for only 10 Location entity array objects of {longitude, latitude, timestamp}).
I was hoping someone could advise me on what I'm doing wrong or if this is usual behavior. Much appreciated.
AppDelegate.swift
calls fetch and prints core data objects when server returns to connected
var fetchedCoreData = self.coreDataManagement.fetchLog()
for dataPoints in fetchedCoreData
{
println(dataPoints)
}
`CoreDataManager.swift handles storing/fetching core data of Location entity
var locations = [NSManagedObject]()
//coordinates passed from AppDelegate
func saveCoords(latCoord: String, longCoord: String, timeCoord: String) {
let appDelegate =
UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Location",
inManagedObjectContext:
managedContext)
let coordsInfo = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
coordsInfo.setValue(latCoord, forKey: "latitude")
coordsInfo.setValue(longCoord, forKey: "longitude")
coordsInfo.setValue(timeCoord, forKey: "timestamp")
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
locations.append(coordsInfo)
}
`
//fetch core data objects
func fetchLog() -> Array<AnyObject> {
let appDelegate =
UIApplication.sharedApplication().delegate as AppDelegate
let fetchRequest = NSFetchRequest(entityName: "Location")
fetchRequest.returnsObjectsAsFaults = false;
var fetchResults = appDelegate.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil)
return fetchResults! as Array<AnyObject>
}
`
Related
I am using CoreData with swift,I am facing an issue in core data while fetching.
I have an Entity with 3 attributes. I am able to save the data Successfully in attributes. only i want to fetch Data from one attribute
Image for Entity
1) Create object of ManagedObject like,
var objModel = [NSManagedObject]()
then fetch data like,
func loadData()
{
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let fetchReq = NSFetchRequest(entityName: "Student") // Your entity
var fetchResult = [NSManagedObject]()
let err : NSError! = nil
do{
fetchResult = try context.executeFetchRequest(fetchReq) as! [NSManagedObject]
self.objModel = fetchResult
self.tblList.reloadData()
}
catch{
print(err)
}
} // Call this loadData() in ViewDidLoad
Then you can get record in CellForRow method of tableview like,
self.objModel[indexPath.row].valueForKey("parent_id")
self.objModel[indexPath.row].valueForKey("task_id")
Hope this helps you.
I struggle with with building a To do app that will download activities from Parse , save them with Core Data and then they will be showed on Apple Watch. I'd like to ask if this is a more or less proper approach to do it:
In viewWillLoad we check if there is an internet connection:
if TRUE we loop over activities in core data and compare them with those from Parse
if they compare we do nothing and prepare cells using info from Core Data
if they do not compare we add them to Core data and prepare cells
if FALSE we prepare cells with info from Core Data
I'm trying to implement my way, but have a problem. Data fetched from parse shown only at the second launch of app. The do not fetch and show at the same time.
My properties
var medicines : [Medicine] = [Medicine]()
var frc :NSFetchedResultsController!
var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Medicine")
My methods to get the data:
// MARK: - Fetching
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 {
//save to Core Data
medicine.setValue(name, forKey: "name")
medicine.setValue(amount, forKey: "amount")
do {
try self.context.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
}
}
}
}
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 call them in viewWillAppear:
if Reachability.isConnectedToNetwork() {
//fetching data from Parse
fetchFromParse()
fetchFromCoreData()
} else {
//fetching data from Core data
fetchFromCoreData()
logOutButton.enabled = false
}
A better approach is to set up a background task to fetch the data with Parse and stick new entries in your core data store, and when new items are detected, to refresh the table on the main thread.
It's my first time using core data. I'm trying to use it to store basic info about my user (if he's logged in through parse.com). So far so good with writing to core data, however, I'm struggling to get the data back. I'm able to print out the data as a [NSManagedObject], but I can't get the data into the different types ( String, Bool, and UIImage). How can I do this?
Saving Data
func saveUser(username : String, proPic : UIImage?){
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let entity = NSEntityDescription.entityForName("User",
inManagedObjectContext:
managedContext)
let person = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
//3
person.setValue(username, forKey: "username")
person.setValue(true, forKey: "isLoggedIn")
person.setValue(proPic, forKey: "profilePic")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
}
Getting Data Back
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"UserInfo")
//3
var error: NSError?
let fetchedResults =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as? [NSManagedObject]
You can use valueForKey similar way you used setValue before. Then you need to deal with the fact that it returns AnyObject.
Another option is to generate custom NSManagedObject subclass. Select your entity in the model editor and in the top menu go to Editor->Create NSManagedObjectSubclass... It will navigate you through the steps. Once you have that, you will have custom class with properties of appropriate type for each entity attribute.
I have a core data model, where I added entity named CurrentLevel and an attribute called currentLevel and of int16 type. I am trying to save a simple integer into it like this:
func saveCurrentLevel(cLevel: Int16){
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("CurrentLevel",
inManagedObjectContext:
managedContext)
let curLevel = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
curLevel.setValue(NSNumber(short: cLevel), forKey: "currentLevel")
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
}
and this is my method for fetching
func fetchTheStuff() {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"CurrentLevel")
//3
var error: NSError?
var fetchedResults =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as? [NSManagedObject]
if let results = fetchedResults {
println(results)
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
I need that the fetched result would be just a simple integer and I cant find a way with core data to do so. Anyone know how ad/or what I am doing wrong?
executeFetchRequest() returns an array of managed objects.
You have to get a single element (e.g. the first), then retrieve the
value of the "currentLevel" attribute (which is a NSNumber)
and finally extract the Int16:
if let results = fetchedResults {
if count(results) > 0 {
let curLevel = results[0] // NSManagedObject
if let num = curLevel.valueForKey("currentLevel") as? NSNumber {
let cLevel = num.shortValue // Int16
println(cLevel)
} else {
println("level not set")
}
} else {
println("no objects found")
}
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
Instead of Key-Value coding with setValue/valueForKey() you can also
let Xcode create NSManagedObject subclasses. If you activate
the "use scalar properties for primitive data types" option then
you can access its
#NSManaged var currentValue: Int16
property directly.
With Objective-C you need to store the int as a NSNumber when using Core Data. So if I was using an int, I would do it like this:
coreDataClass.number = [NSNumber numberWithInt:100];
I'm not sure if it's the same with Swift though.
Here's how I'm saving the data
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Theme", inManagedObjectContext: managedContext)
let themeObj = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
themeObj.setValue(num, forKey: "themeNumber")
var error: NSError?
if !managedContext.save(&error)
{
println("Could not save \(error), \(error?.userInfo)")
}
And then loading it
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest(entityName:"Theme")
var resultArr = [NSManagedObject]()
var error: NSError?
let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject]?
if let results = fetchedResults
{
resultArr = results
}
else
{
println("Could not fetch \(error), \(error!.userInfo)")
}
theme = resultArr[0].valueForKey("themeNumber") as Int
My data model is just the entity Theme with one attribute, themeNumber which is an Integer 16. If I delete the app from the simulator, it loads the correct theme. However, if I change it and run it again... nothing. Any ideas?
You don't need to use setValue. Typically you would do something like this:
themeObj.themeNumber = num
So to fix your problem, you need to actually update the core data object. I just realized that you probably didn't set the themeNumber by the property because you don't have the NSManagedObject subclass setup for your entity. I'll write try to write the fix for how you have it setup.
theme = resultArr[0] as NSManagedObject
theme.setValue(num, forKey: "themeNumber")
if !managedContext.save(&error)
{
println("Could not save \(error), \(error?.userInfo)")
}
After you save it, see if it has the new value that you are looking for.