How to Sum in Core Data - core-data

I have a data model like this:
I want to get a sum list by group by catalog.item,money.year,money.month, and I have tried to do it in several ways which is found in internet, but I failed.
I have tried "let fetchRequest = NSFetchRequest(entityName:"CashFlow")" and "let fetchRequest = NSFetchRequest< CashFlow >(entityName:"CashFlow")"
It is always the same error:Printing description of fetchRequest:
expression produced error: error: /var/folders/8j/g0yb8vwx23z2s1qykxz2q7hh0000gn/T/expr51-6487f6..swift:1:65: error: use of undeclared type 'CoreData'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer>(bitPattern: 0x127497460)!.pointee)
class MonthlySum {
public var year:Int16 = 0
public var month:Int16 = 0
public var emoji:String = ""
public var item:String = ""
public var budget:Int16 = 0
public var total:Int16 = 0
}
//I also have tried to define MonthlySum as NSManagedObject
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"CashFlow")
// Set the batch size to a suitable number.
//fetchRequest.fetchBatchSize = 32
fetchRequest.predicate = NSPredicate(format: "money.year = %d and money.month = %d",year,month)
// sort by day
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "money.cata.item", ascending: true)]
//group by day for sum
//fetchRequest.propertiesToGroupBy = ["money.cata.emoji","money.cata.item","money.budget"]
var expressionDescriptions = [AnyObject]()
var expD = NSExpressionDescription()
// select year
expD.name = "year"
expD.expression = NSExpression(forKeyPath: "money.year")
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
// select month
expD.name = "month"
expD.expression = NSExpression(forKeyPath: "money.month")
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
// select category item
expD.name = "item"
expD.expression = NSExpression(forKeyPath: "money.cata.item")
expD.expressionResultType = .stringAttributeType
expressionDescriptions.append(expD)
// select category emoji
expD.name = "emoji"
expD.expression = NSExpression(forKeyPath: "money.cata.emoji")
expD.expressionResultType = .stringAttributeType
expressionDescriptions.append(expD)
// select month
expD.name = "budget"
expD.expression = NSExpression(forKeyPath: "money.budget")
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
//select #sum.amount as dailysum
expD = NSExpressionDescription()
expD.name = "total"
expD.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "amount")])
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
fetchRequest.propertiesToFetch = expressionDescriptions
fetchRequest.resultType = .dictionaryResultType
var result = [MonthlySum]()
let m = MonthlySum()
do {
let fetchResult = try viewContext.fetch(fetchRequest) as! [MonthlySum]
/*
for item in fetchResult {
m.budget = item.value(forKey: "budget") as! Int16
m.emoji = item.value(forKey: "emoji") as! String
m.item = item.value(forKey: "item") as! String
m.month = item.value(forKey: "month") as! Int16
m.total = item.value(forKey: "total") as! Int16
m.year = item.value(forKey: "year") as! Int16
result.append(m)
} */
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}

no matter what it works as this:
let fetchRequest = NSFetchRequest<NSDictionary>(entityName:"Trade")
fetchRequest.predicate = NSPredicate(format: "year = %d and month = %d",year,month)
// sort by day
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "day", ascending: true)]
//group by day for sum
fetchRequest.propertiesToGroupBy = ["day"]
var expressionDescriptions = [AnyObject]()
var expD = NSExpressionDescription()
// select day
expD.name = "day"
expD.expression = NSExpression(forKeyPath: "day")
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
//select #sum.amount as dailysum
expD = NSExpressionDescription()
expD.name = "total"
expD.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "amount")])
expD.expressionResultType = .integer16AttributeType
expressionDescriptions.append(expD)
fetchRequest.propertiesToFetch = expressionDescriptions
fetchRequest.resultType = .dictionaryResultType
var result = [Int:String]()
do {
let fetchResult = try viewContext.fetch(fetchRequest)
for item in fetchResult {
result[item.value(forKey: "day") as! Int] = String(describing: item.value(forKey: "total") as! Int)}
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
return result

Related

fetch core data string and place in a label (Swift4)

I am trying to call 2 different core data strings and place them each on separate labels. Right now I am getting the error Cannot invoke initializer for type 'init(_:)' with an argument list of type '([NSManagedObject])'. This error is coming from j1.text = String(itemsName). I added both view controllers for saving and displaying.
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet var j1 : UITextField!
#IBOutlet var j2 : UITextField!
#IBAction func save(){
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Team", in : context)!
let theTitle = NSManagedObject(entity: entity, insertInto: context)
theTitle.setValue(j1.text, forKey: "score")
theTitle.setValue(j2.text, forKey: "alba")
do {
try context.save()
}
catch {
print("Tom Corley")
}
}}
class twoVC: UIViewController {
#IBOutlet var j1 : UILabel!
#IBOutlet var j2 : UILabel!
var itemsName : [NSManagedObject] = []
var itemsName2 : [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Team")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "score", ascending: true)]
let fetchRequest2 = NSFetchRequest<NSManagedObject>(entityName: "Team")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "alba", ascending: true)]
do {
itemsName = try context.fetch(fetchRequest)
itemsName2 = try context.fetch(fetchRequest2)
if let score = itemsName[0].value(forKey: "score") {
j1.text = (score as! String)
}
if let alba = itemsName2[0].value(forKey: "alba") {
j2.text = (alba as? String)
}
}catch {
print("Ashley Tisdale")
}
}}
Loop over the result from the fetch and append to a string that is then used as value for the label, this goes inside the do{...} where you do the fetch today. Note that I am only using one fetch request here.
itemsName = try context.fetch(fetchRequest)
var mergedScore: String = ""
var mergedAlba: String = ""
for item in itemsName {
if let score = item.value(forKey: "score") as? String {
mergedScore.append(score)
mergedScore.append(" ") //separator
}
if let alba = item.value(forKey: "alba") as? String {
mergedScore.append(alba)
mergedScore.append(" ") //separator
}
}
j1.text = mergedScore
j2.text = mergedAlba
Try this one it's Working for me Swift 4 I think You need to store the value as int which are used as sortDescriptor.
func FetchManagedObjectFromDatabaseForStoreData(Entity :NSEntityDescription) ->
[NSManagedObject]
{
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
// Add Sort Descriptor
let sortDescriptor = NSSortDescriptor(key: "order", ascending: true)
let sortDescriptor1 = NSSortDescriptor(key: "is_favourite", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor,sortDescriptor1]
// Create Entity Description
fetchRequest.entity = Entity
let result : [NSManagedObject] = []
// Execute Fetch Request
do{
let result = try appDelegate.managedObjectContext.fetch(fetchRequest) as! [NSManagedObject]
if result.count > 0
{
return result
}
else
{
// return result
}
}
catch{
let fetchError = error as NSError
print(fetchError)
}
return result
}
For Fetch Data
// Create Entity Description
let entityDescription = NSEntityDescription.entity(forEntityName: "Your Entity Name Here", in: appDel.managedObjectContext)
let DataObject = FetchManagedObjectFromDatabaseForStoreData(Entity: entityDescription!)
//Convert Array of NSManagedObject into array of [String:AnyObject]
for item in DataObject{
let keys = Array(item.entity.attributesByName.keys)
// Here is your result
print((item.dictionaryWithValues(forKeys: keys) as NSDictionary).value(forKey: "id") as Any) // And so On Whatewer you Fetch
}

How can I filter core data based records to avoid the appearance of duplicates. (Swift 4)

I am pulling records from a core data entity. The records each contain "brand", "model", "size", and "price". There are various size and cost options.
I want to see unique records of "brand" and "model". As you can see from the screenshot, that is not working.
This is a code snip I've written so far:
let sortDescriptor: NSSortDescriptor!
let defaults: UserDefaults = UserDefaults.standard
if defaults.integer(forKey: "sequenceSwitchValue") == 0 {
sortDescriptor = NSSortDescriptor(key: "brand", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
} else {
sortDescriptor = NSSortDescriptor(key: "brand", ascending: false, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
}
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: filmEntity)
request.returnsDistinctResults = true
request.propertiesToFetch = ["brand", "model"]
request.sortDescriptors = [sortDescriptor]
request.predicate = nil
do {
films = try context.fetch(request) as! [FilmEntity]
} catch let error as NSError {
print("Error While Fetching Data From DB: \(error.userInfo)")
}

Xcode 8 Swift 3 Core Data too many ent

I'm just starting to learn to work with Core Data in Swift 3. I am trying to save and retrieve some variables for a basic game to learn, however every time it saves/retrieves it creates an additional value. Now i'm up to 75 entries, each with a set of the variables. I'd like to have 1 that i can work with. Is there a way to keep the total to 1 (delete the old before new one saved).
Or is there a better way to data handle between viewControllers?
Thanks.
func retrieveCoreData() {
// let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Variables")
request.returnsObjectsAsFaults = false
do
{
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject]
{
atHome = result.value(forKey: "atHome") as! Int
playerGold = result.value(forKey: "playerGold") as! Int
battleBoss = result.value(forKey: "battleBoss") as! Bool
enemyAttack = result.value(forKey: "enemyAttack") as! Int
enemyDefense = result.value(forKey: "enemyDefense") as! Int
enemyHealth = result.value(forKey: "enemyHealth") as! Int
enemyHealthMax = result.value(forKey: "enemyHealthMax") as! Int
inBattle = result.value(forKey: "inBattle") as! Bool
playerAttack = result.value(forKey: "playerAttack") as! Int
playerDefense = result.value(forKey: "playerDefense") as! Int
playerGold = result.value(forKey: "playerGold") as! Int
playerHealth = result.value(forKey: "playerHealth") as! Int
playerLevel = result.value(forKey: "playerLevel") as! Int
playerLevelUpgradeValue = result.value(forKey: "playerLevelUpgradeValue") as! Int
}
}
}
catch {
fatalError("Failed to recover CoreData: \(error)")
}
}
Here is a list of the values printed: (note "p12")
<Variables: 0x1466d150> (entity: Variables; id: 0x14644960 <x-coredata://2E613846-F77C-4492-B27E-5A79AEC58949/Variables/p12> ; data: {
atHome = 1;
battleBoss = 0;
enemyAttack = 1;
enemyDefense = 1;
enemyHealth = 1;
enemyHealthMax = 1;
inBattle = 0;
playerAttack = 6;
playerDefense = 3;
playerGold = 0;
playerHealth = 200;
playerHealthMax = 0;
playerLevel = 1;
playerLevelUpgradeValue = 350;
})

CORE DATA: memory not being released even after manually faulting and doing a managed object reset during xml parsing of large mb file

I am parsing large kml file(18 MB) using NSXMLParser and simultaneously storing coordinates of every place in core data, what i am observing is memory is not being released after parsing 3/4th of the file memory piles up and application crashes, i have tried most of the answers given on stackoverflow but were not useful. Any help is mostly welcomed.
var currentElement : String = ""
var place:Place?
var polygon:Polygon?
var placeName = ""
var shouldAddCoordinates = false
private lazy var privateManagedObjectContext: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext.persistentStoreCoordinator
return managedObjectContext
}()
override init() {
super.init()
}
// Xml Parser delegate methods
func parserDidStartDocument(_ parser: XMLParser) {
print("..Xml parsing has started")
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
currentElement = elementName
if elementName == "Placemark" {
place = NSEntityDescription.insertNewObject(forEntityName: "Place", into: privateManagedObjectContext) as? Place
place?.placeName = ""
}
if elementName == "Polygon" {
polygon = NSEntityDescription.insertNewObject(forEntityName: "Polygon", into: privateManagedObjectContext) as? Polygon
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %#", placeName)
do{
let fetchResult = try privateManagedObjectContext.fetch(fetchRequest) as [Place]
polygon?.place = place
polygon?.placeName = placeName
shouldAddCoordinates = fetchResult.first?.placeName == placeName ? true:false
}
catch{}
}
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %#", placeName)
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest) as [Place]
shouldAddCoordinates = fetchResult?.first?.placeName == placeName ? true:false
}
if elementName == "name"{
placeName = ""
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement = elementName
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Polygon")
let sortDescriptor = NSSortDescriptor(key: "polygonID", ascending: true )
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [Polygon]
if fetchResult?.count == 0{
polygon?.polygonID = 1
}
else{
polygon?.polygonID = Int64(fetchResult!.count)
}
polygon?.place = place
}
if elementName == "coordinates" || elementName == "Polygon" || elementName == "name"{
if self.privateManagedObjectContext.hasChanges{
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
}
}
else if elementName == "Placemark"{
placeName = ""
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
privateManagedObjectContext.reset()
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if currentElement == "name" {
if string == "\n" {
return
}
place?.placeName? += string
placeName += string
}
if currentElement == "coordinates"{
if shouldAddCoordinates {
privateManagedObjectContext.performAndWait{
if string == "\n" {
return
}
else{
let coordinates = NSEntityDescription.insertNewObject(forEntityName: "Coordinates", into: self.privateManagedObjectContext) as! Coordinates
let longitude = (string.components(separatedBy: ",") as [NSString]).first!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitude = (string.components(separatedBy: ",") as [NSString]).last!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitudeDegrees : CLLocationDegrees = latitude.doubleValue
let longitudeDegrees: CLLocationDegrees = longitude.doubleValue
coordinates.latitude = latitudeDegrees as NSNumber?
coordinates.longitude = longitudeDegrees as NSNumber?
coordinates.coordinatesDate = Date() as NSDate
coordinates.polygon = self.polygon
print("\(String(describing: coordinates.polygon?.placeName!)) has coordinates \(coordinates.latitude!),\(coordinates.longitude!)")
}
}
}
}
}
func parserDidEndDocument(_ parser: XMLParser) {
print("..Parser has finished parsing..")
}
func getManagedObject() -> NSManagedObjectContext{
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
return managedObjectContext
}
func saveCoordinates(){
let url = Bundle.main.url(forResource: "IND_adm1_1", withExtension: "kml")
let xmlParser = XMLParser(contentsOf: url!)
xmlParser?.delegate = self
_ = xmlParser?.parse()
}

Core Data setting all attributes to nil for first time

I am using Xcode 8 with Swift 3
Core Data setting all the attributes to nil for first time on load with no relationships.
Here is the screenshot.
In Console, i am getting this if App is installed for first time. I have deleted and try to run & install from Xcode number of times. Every time it sets all the values to nil.
"author_id" = nil;
"channel_id" = 0;
"created_at" = nil;
desc = nil;
id = 0;
images = nil;
"is_approved" = 0;
"is_bookmarks" = 0;
"is_like" = 0;
"is_wired" = 0;
"like_count" = 0;
link = nil;
"meta_des" = nil;
"post_id" = 0;
pubDate = nil;
"publisher_id" = 0;
"rss_url" = nil;
"share_cat" = nil;
"share_title" = nil;
"tiny_url" = nil;
title = nil;
"title_tag" = nil;
type = nil;
"updated_at" = nil;
url = nil;
Don't understand whats happening there. Anyone has any idea or hint what am i doing wrong or missing here. And this is only happening for "NewsPost" Entity.
Here is the code where i am adding data to core data.
func addData(entityName: String, entityValues: Any) {
var contextt = NSManagedObjectContext()
if #available(iOS 10.0, *) {
contextt = self.persistentContainer.viewContext
} else {
contextt = self.managedObjectContext
}
/// add data
switch entityName {
case EntityName.NewsEntity:
let singlePost = entityValues as! NSDictionary
let id = singlePost.value(forKey: "id") as! NSNumber
let title = singlePost.value(forKey: "title") as! String
let description = singlePost.value(forKey: "description") as! String
let link = singlePost.value(forKey: "link") as! String
let url = singlePost.value(forKey: "url") as! String
let is_approved = singlePost.value(forKey: "is_approved") as! NSNumber
let meta_des = singlePost.value(forKey: "meta_des") as! String
let title_tag = singlePost.value(forKey: "title_tag") as! String
let share_cat = singlePost.value(forKey: "share_cat") as! String
let author_id = singlePost.value(forKey: "author_id") as! String
let type = singlePost.value(forKey: "type") as! String
let publisher_id = singlePost.value(forKey: "publisher_id") as! NSNumber
let channel_id = singlePost.value(forKey: "channel_id")
let share_title = singlePost.value(forKey: "share_title") as! String
let rss_url = singlePost.value(forKey: "rss_url")
let pubDate = singlePost.value(forKey: "pubDate") as! String
let created_at = singlePost.value(forKey: "created_at") as! String
let updated_at = singlePost.value(forKey: "updated_at") as! String
let like_count = singlePost.value(forKey: "like_count") as! NSNumber
let tiny_url = singlePost.value(forKey: "tiny_url") as! String
let publisher = singlePost.value(forKey: "publisher") as! NSDictionary
let pubName = publisher.value(forKey: "name") as! String
let post = NSEntityDescription.insertNewObject(forEntityName: "NewsPost", into: contextt) as! NewsPost
post.id = Int64(id)
post.title = title
post.desc = description
post.link = link
post.url = url
post.is_approved = Int16(is_approved)
post.meta_des = meta_des
post.title_tag = title_tag
post.share_cat = share_cat
post.author_id = author_id
post.type = type
post.publisher_id = Int64(publisher_id)
post.channel_id = (channel_id as? Int64) ?? 0
post.share_title = share_title
post.rss_url = rss_url as? String ?? ""
post.pubDate = pubDate
post.created_at = created_at
post.updated_at = updated_at
post.like_count = Int64(like_count)
post.tiny_url = tiny_url
let images = singlePost.value(forKey: "images") as! NSArray
do {
let data = try JSONSerialization.data(withJSONObject: images, options: .prettyPrinted)
let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
post.images = string as? String
} catch {
}
print("post data -\(post.managedObjectContext)")
break
case EntityName.Categories:
entity.setValue(entityValues[0], forKey: EntityName.Entities.catName)
break
default:
break
}
/// we save our entity
do {
try contextt.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
This is how i am fetching data from Core Data.
func fetchData(entityToFetch: String, completion: #escaping (_ result: [NSManagedObject]?)->()) {
var context = NSManagedObjectContext()
if #available(iOS 10.0, *) {
context = CoreDataStack().persistentContainer.viewContext
} else {
context = DataController().managedObjectContext
}
// Fetching core data
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityToFetch)
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
print("fetch results- \(results as! [NSManagedObject])")
if results.count > 0 {
completion(results as? [NSManagedObject])
} else {
completion(nil)
}
} catch let error {
completion(nil)
print("fetch error -\(error.localizedDescription)")
}
}
Thank in advance.

Resources