NSSet and Core Data - swift

I am trying to save two lists of objects in core data. I have a protocol method which adds my tags as (Tag) and puts them into an array of tags. I am not able to save these objects as I am using an NSSet and the extension (for swift) as:
extension CurrentTransaction {
func addTagObject(value:Tag) {
var items = self.mutableSetValueForKey("tagMembers");
items.addObject(value)
}
func removeTagObject(value:Tag) {
var items = self.mutableSetValueForKey("tagMembers");
items.removeObject(value)
}
}
The two objects from core data I am trying to save are:
class Pic: NSManagedObject {
#NSManaged var picName: String!
#NSManaged var picNumber: String!
#NSManaged var currentTransaction: CurrentTransaction
class func createInManagedObjectContext(moc: NSManagedObjectContext, name: String, number: String) -> Pic {
let newPic = NSEntityDescription.insertNewObjectForEntityForName("Pic", inManagedObjectContext: moc) as! Pic
newPic.picName = name
newPic.picNumber = number
return newPic
}
}
class Tag:
class Tag: NSManagedObject {
#NSManaged var tagName: String!
#NSManaged var tagNumber: String!
#NSManaged var currentTransaction: CurrentTransaction
class func createInManagedObjectContext(moc: NSManagedObjectContext, name: String, number: String) -> Tag {
let newTag = NSEntityDescription.insertNewObjectForEntityForName("Tag", inManagedObjectContext: moc) as! Tag
newTag.tagName = name
newTag.tagNumber = number
return newTag
}
}
class currentTransaction:
class CurrentTransaction: NSManagedObject {
#NSManaged var destinationPIC: String
#NSManaged var sourcePIC: String
#NSManaged var nvdNumber: String
#NSManaged var numberOfAnimals: NSNumber
#NSManaged var requestType: String
#NSManaged var date: NSDate
#NSManaged var tagMembers: NSSet
#NSManaged var picMembers: NSSet?
class func createInManagedObjectContext(moc: NSManagedObjectContext, toPic: String, fromPic: String, nvd: String, numAnimals: NSNumber, request: String, date: NSDate, tags: NSSet, pics: NSSet) -> CurrentTransaction {
let newTransaction = NSEntityDescription.insertNewObjectForEntityForName("CurrentTransaction", inManagedObjectContext: moc) as! CurrentTransaction
newTransaction.destinationPIC = toPic
newTransaction.sourcePIC = fromPic
newTransaction.nvdNumber = nvd
newTransaction.numberOfAnimals = numAnimals
newTransaction.requestType = request
newTransaction.tagMembers = tags
newTransaction.picMembers = pics
newTransaction.date = date
return newTransaction
}
}
When I call the CurrentTransaction.addTagObject(tag:Tag) I get "Cannot invoke 'addTagObject' with an argument list of type '(Tag)'
Here is my addTags protocol method:
func addTags(tag: Tag) {
//println("IN ADD TAGS")
//println(tag.tagNumber)
self.tagList.append(tag)
CurrentTransaction.addTagObject(tag) //Error on this line
}

Reason: addTagObject() is not defined as class function and cannot be invoked on class CurrentTransaction. If you intended to use it as class fucntion, change it to:
class func addTagObject(value:Tag) {
var items = self.mutableSetValueForKey("tagMembers");
items.addObject(value)
}

Related

Core Data 'to-many' relationship save object in a dictionary not a set

I'm working with Core Data and have been using this hackingWithSwift tutorial. I have two entities with a one-to-many relationship.
Country Entity
extension Country {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Country> {
return NSFetchRequest<Country>(entityName: "Country")
}
#NSManaged public var id: UUID?
#NSManaged public var fullName: String?
#NSManaged public var shortName: String?
#NSManaged public var candy: NSSet?
public var wrappedShortName: String {
shortName ?? "Unknown Country"
}
public var wrappedFullName: String {
fullName ?? "Unknown Country"
}
public var candyArray: [Candy] {
let set = candy as? Set<Candy> ?? []
return set.sorted {
$0.wrappedName < $1.wrappedName
}
}
}
// MARK: Generated accessors for candy
extension Country {
#objc(addCandyObject:)
#NSManaged public func addToCandy(_ value: Candy)
#objc(removeCandyObject:)
#NSManaged public func removeFromCandy(_ value: Candy)
#objc(addCandy:)
#NSManaged public func addToCandy(_ values: NSSet)
#objc(removeCandy:)
#NSManaged public func removeFromCandy(_ values: NSSet)
}
Candy Entity
extension Candy {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Candy> {
return NSFetchRequest<Candy>(entityName: "Candy")
}
#NSManaged public var id: UUID?
#NSManaged public var name: String?
#NSManaged public var origin: Country?
public var wrappedName: String {
name ?? "Unknown Candy"
}
}
So Country can have many Candy.
What I'm wondering is if it is possible that when I create a Candy and save it that rather than being added to the NSSet of Candy's in the Country entity is it possible to save it to a NSDictionary or any other collection type besides NSSet? Not sure if I just change
#objc(addCandy:)
#NSManaged public func addToCandy(_ values: NSSet) //Change to NSDictionary
#objc(removeCandy:)
#NSManaged public func removeFromCandy(_ values: NSSet) //Change to NSDictionary
If this works, cause I would like the Entity id property to be the key and the object to be the value. Not sure if this is possible.
This is how they are being added
let candy3 = Candy(context: viewContext)
candy3.name = "Twix"
candy3.orgin = Country(context: viewContext)
candy3.orgin?.shortName = "UK"
candy3.orgin?.fullName = "United Kingdom"
let candy4 = Candy(context: viewContext)
candy4.name = "Toblerone"
candy4.orgin = Country(context: viewContext)
candy4.orgin?.shortName = "CH"
candy4.orgin?.fullName = "Switzerland"
try? viewContext.save()
Please ask any questions if this doesn't make sense.
You can use Transformable to encode and decode a Dictionary but you can't change a relationship to a dictionary

Unable to set the value of an NSDecimalNumber attribute of a Core Data model in Swift

I've got a core data model called AccountMO, which contains an attribute of NSSet? called holdings which contains a set of another core data model called HoldingMO. HoldingMO has an attribute called holdingValue which is an NSDecimalNumber type.
The AccountMO model has an attribute called accountValue of NSDecimalNumber type, which is supposed to be the sum of the HoldingMO.holdingValue attribute.
I gave up trying to use Core Data derived attributes because the compiler just won't build if there's more than one derived attribute in a model, and I need several summary attributes for other NSSet attributes as well.
I can calculate the sum of HoldingMO.holdingValue like this:
let sum = holdings?.value(forKeyPath: "#sum.holdingValue")
This results in that ever not so useful type "Any", which I have to convert to NSDecimal like so:
let sum = holdings?.value(forKeyPath: "#sum.holdingValue") as! Decimal
accountValue = NSDecimalNumber(decimal: sum)
I've also tried to do it like this:
if holdings?.count ?? 0 > 0 {
let hlds = holdings as! Set<HoldingMO>
let sum = hlds.map {$0.holdingValue}.reduce(0) {$0 + $1.decimalValue }
accountValue = NSDecimalNumber(decimal: sum)
}
But either way where I try to set accountValue the app always crashes the app with:
"Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
I've searched a lot of solutions, and it seems this is caused by forcing an unwrap on an optional property. I've done the best I can to eliminate any optionals, (other than the optional NSSet? for the holdings set.)
Any ideas?
Here's the AccountMO model:
//
// AccountMO+CoreDataProperties.swift
// AdvisorBook v3
//
// Created by Chris Browning on 6/28/20.
// Copyright © 2020 Browning Financial, Inc. All rights reserved.
//
//
import Foundation
import CoreData
import Cocoa
extension AccountMO {
#nonobjc public class func fetchRequest() -> NSFetchRequest<AccountMO> {
return NSFetchRequest<AccountMO>(entityName: "Account")
}
#NSManaged public var accountName: String?
#NSManaged public var accountNumber: String?
#NSManaged public var accountRegType: TypeOfAccountReg
#NSManaged public var accountTitle: String?
#NSManaged public var accountType: TypeOfAccount
#NSManaged public var accountValue: NSDecimalNumber
#NSManaged public var billingType: TypeOfBilling
#NSManaged public var cash: NSDecimalNumber?
#NSManaged public var clearingFirm: TypeOfClearingFirm
#NSManaged public var closedDate: Date?
#NSManaged public var openDate: Date?
#NSManaged public var company: String?
#NSManaged public var cost: NSDecimalNumber?
#NSManaged public var created: NSDate
#NSManaged public var fee: NSDecimalNumber?
#NSManaged public var gain: NSDecimalNumber?
#NSManaged public var gainPerc: NSDecimalNumber?
#NSManaged public var gc: NSDecimalNumber?
#NSManaged public var holdingCount: Int32
#NSManaged public var minCash: NSDecimalNumber?
#NSManaged public var modified: NSDate
#NSManaged public var restricted: Bool
#NSManaged public var status: TypeOfStatus
#NSManaged public var subNumber: String?
#NSManaged public var tradeCount: Int32
#NSManaged public var ytdGC: NSDecimalNumber?
#NSManaged public var ytdGCPerc: NSDecimalNumber?
#NSManaged public var ytdTradeCount: Int32
#NSManaged public var ytdYear: Int32
#NSManaged public var qualified: TypeOfQualified
#NSManaged public var advisors: NSSet?
#NSManaged public var contacts: NSSet?
#NSManaged public var holdings: NSSet?
#NSManaged public var trades: NSSet?
#NSManaged public var feeSchedule: FeeScheduleMO?
override public func awakeFromInsert() {
let app = NSApplication.shared.delegate as! AppDelegate
let moc : NSManagedObjectContext = ((NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext)
let advisorFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Advisor")
let investFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Investment")
investFetch.predicate = NSPredicate(format: "symbol == %#", "CASH")
do {
let fetchedAdvisors = try moc.fetch(advisorFetch) as! [AdvisorMO]
if fetchedAdvisors.count > 0 {
let advisor = fetchedAdvisors[0]
addToAdvisors(advisor)
let fetchedInvestments = try moc.fetch(investFetch) as! [InvestmentMO]
if fetchedAdvisors.count > 0 {
let holding = app.myViewController.newHolding()
holding.coreCash = true
holding.investment = fetchedInvestments[0]
holding.investedDate = Date()
addToHoldings(holding)
app.myViewController.accountHoldingsArrayController.defaultFetchRequest()
}
}
created = NSDate()
modified = NSDate()
} catch {
fatalError("Failed to fetch advisors: \(error)")
}
}
#objc public var statusString: String? {
get {
return status.displayName
}
set {
status = TypeOfStatus(withname: newValue ?? "OPEN") ?? TypeOfStatus.OPEN
}
}
#objc public var clearingFirmString: String? {
get {
return clearingFirm.displayName
}
set {
clearingFirm = TypeOfClearingFirm(withname: newValue ?? "DIRECT") ?? TypeOfClearingFirm.DIRECT
}
}
#objc public var billingTypeString: String? {
get {
return billingType.displayName
}
set {
billingType = TypeOfBilling(withname: newValue ?? "COMMISSION") ?? TypeOfBilling.COMMISSION
}
}
#objc public var accountTypeString: String? {
get {
return accountType.displayName
}
set {
accountType = TypeOfAccount(withname: newValue ?? "CASH") ?? TypeOfAccount.CASH
}
}
#objc public var accountRegTypeString: String? {
get {
return accountRegType.displayName
}
set {
accountRegType = TypeOfAccountReg(withname: newValue ?? "OTHER") ?? TypeOfAccountReg.OTHER
}
}
#objc public var qualifiedString: String? {
get {
return qualified.displayName
}
set {
willChangeValue(forKey: "qualified")
if newValue?.starts(with: "NON") ?? false {
qualified = TypeOfQualified.NONQUALIFIED
} else {
qualified = TypeOfQualified.QUALIFIED
}
didChangeValue(forKey: "qualified")
}
}
func refresh() {
if holdings?.count ?? 0 > 0 {
//accountValue = holdings?.value(forKeyPath: "#sum.holdingValue?") as! NSDecimalNumber
let numberString = accountNumber ?? "No number"
let titleString = accountTitle ?? "No title"
let accountString = numberString + " " + titleString
print(accountString)
if holdings?.count ?? 0 > 0 {
let hlds = holdings as! Set<HoldingMO>
let sum = hlds.map {$0.holdingValue}.reduce(0) {$0 + $1.decimalValue }
accountValue = NSDecimalNumber(decimal: sum)
}
}
}
func sumHoldings() throws -> Decimal {
return holdings?.value(forKeyPath: "#sum.holdingValue") as! Decimal
}
override public func willSave() {
if changedValues()["modified"] == nil {
modified = NSDate()
} else {
super.willSave()
}
}
override public func awakeFromFetch() {
//refresh()
}
}
// MARK: Generated accessors for advisors
extension AccountMO {
#objc(addAdvisorsObject:)
#NSManaged public func addToAdvisors(_ value: AdvisorMO)
#objc(removeAdvisorsObject:)
#NSManaged public func removeFromAdvisors(_ value: AdvisorMO)
#objc(addAdvisors:)
#NSManaged public func addToAdvisors(_ values: NSSet)
#objc(removeAdvisors:)
#NSManaged public func removeFromAdvisors(_ values: NSSet)
}
// MARK: Generated accessors for contacts
extension AccountMO {
#objc(addContactsObject:)
#NSManaged public func addToContacts(_ value: ContactMO)
#objc(removeContactsObject:)
#NSManaged public func removeFromContacts(_ value: ContactMO)
#objc(addContacts:)
#NSManaged public func addToContacts(_ values: NSSet)
#objc(removeContacts:)
#NSManaged public func removeFromContacts(_ values: NSSet)
}
// MARK: Generated accessors for holdings
extension AccountMO {
#objc(addHoldingsObject:)
#NSManaged public func addToHoldings(_ value: HoldingMO)
#objc(removeHoldingsObject:)
#NSManaged public func removeFromHoldings(_ value: HoldingMO)
#objc(addHoldings:)
#NSManaged public func addToHoldings(_ values: NSSet)
#objc(removeHoldings:)
#NSManaged public func removeFromHoldings(_ values: NSSet)
}
// MARK: Generated accessors for trades
extension AccountMO {
#objc(addTradesObject:)
#NSManaged public func addToTrades(_ value: TradeMO)
#objc(removeTradesObject:)
#NSManaged public func removeFromTrades(_ value: TradeMO)
#objc(addTrades:)
#NSManaged public func addToTrades(_ values: NSSet)
#objc(removeTrades:)
#NSManaged public func removeFromTrades(_ values: NSSet)
}
And the HoldingMO model:
//
// HoldingMO+CoreDataProperties.swift
// AdvisorBook v3
//
// Created by Chris Browning on 5/20/20.
// Copyright © 2020 Browning Financial, Inc. All rights reserved.
//
//
import Foundation
import CoreData
extension HoldingMO {
#nonobjc public class func fetchRequest() -> NSFetchRequest<HoldingMO> {
return NSFetchRequest<HoldingMO>(entityName: "Holding")
}
#NSManaged public var cost: NSDecimalNumber
#NSManaged public var coreCash: Bool
#NSManaged public var costPrice: NSDecimalNumber
#NSManaged public var created: NSDate
#NSManaged public var gain: NSDecimalNumber
#NSManaged public var gainPerc: NSDecimalNumber
#NSManaged public var holdingAccountType: Int32
#NSManaged public var holdingPrice: NSDecimalNumber
#NSManaged public var holdingValue: NSDecimalNumber
#NSManaged public var investedDate: Date?
#NSManaged public var isStockOrMF: Bool
#NSManaged public var isStockOrMFOrUIT: Bool
#NSManaged public var modified: NSDate
#NSManaged public var override: Bool
#NSManaged public var quantity: NSDecimalNumber
#NSManaged public var soldDate: Date?
#NSManaged public var status: TypeOfStatus
#NSManaged public var subAccount: String?
#NSManaged public var account: AccountMO?
#NSManaged public var investment: InvestmentMO?
#NSManaged public var trades: NSSet?
#objc public var change: NSDecimalNumber? {
get {
//let amt = (investment?.priceChange?.decimalValue ?? 0) as NSDecimalNumber
return _change
}
set {
_change = newValue ?? 0
}
}
#objc public var statusString: String? {
get {
return status.displayName ?? "OPEN"
}
set {
status = TypeOfStatus(withname: newValue ?? "OPEN") ?? TypeOfStatus.OPEN
hideClosed = isOpen()
}
}
#objc public var hideClosed: Bool {
get {
return _hideclosed
}
set {
_hideclosed = newValue
}
}
override public func awakeFromInsert() {
created = NSDate()
modified = NSDate()
investedDate = Date()
}
override public func awakeFromFetch() {
refresh()
}
func refresh() {
if status == TypeOfStatus.OPEN {
if investment != nil {
holdingPrice = investment?.price as! NSDecimalNumber
let amt = (investment?.priceChange.decimalValue ?? 0) as NSDecimalNumber
change = quantity.multiplying(by: amt)
isStockOrMF = ((investment?.isStockOrMF) != nil)
let val = holdingPrice.multiplying(by: quantity)
holdingValue = val
holdingValue = holdingPrice.multiplying(by: quantity)
if investment?.investmentType == TypeOfInvestment.CASH {
cost = holdingValue
}
gain = holdingValue.subtracting(cost)
print(gain)
if gain.decimalValue != 0 {
gainPerc = gain.dividing(by: cost)
} else {
gainPerc = 0
}
modified = NSDate()
account?.refresh()
}
} else {
if investment != nil {
isStockOrMF = ((investment?.isStockOrMF) != nil)
holdingValue = holdingPrice.multiplying(by: quantity )
if investment?.investmentType == TypeOfInvestment.CASH {
cost = holdingValue
}
gain = holdingValue.subtracting(cost )
gainPerc = gain.dividing(by: cost )
modified = NSDate()
account?.refresh()
}
}
}
override public func willSave() {
if changedValues()["modified"] == nil {
modified = NSDate()
} else {
super.willSave()
}
}
}
// MARK: Generated accessors for trades
extension HoldingMO {
#objc(addTradesObject:)
#NSManaged public func addToTrades(_ value: TradeMO)
#objc(removeTradesObject:)
#NSManaged public func removeFromTrades(_ value: TradeMO)
#objc(addTrades:)
#NSManaged public func addToTrades(_ values: NSSet)
#objc(removeTrades:)
#NSManaged public func removeFromTrades(_ values: NSSet)
}
I solved this issue by just dropping the use of the Core Data attribute in favor of a simple #objc property like this:
var _accountval: NSDecimalNumber = 0
#objc public var accountVal: NSDecimalNumber {
get {
return _accountval
}
set {
willChangeValue(forKey: "accountVal")
_accountval = newValue
didChangeValue(forKey: "accountVal")
}
}
Instead of
#NSManaged public var accountValue: NSDecimalNumber
Now I can call this:
func refresh() {
if holdings != nil && holdings?.count ?? 0 > 0 {
var sum: Decimal = 0
for holding in holdings as! Set<HoldingMO> {
if holding.isOpen() {
sum += holding.holdingValue.decimalValue
}
}
accountVal = NSDecimalNumber(decimal: sum)
}
}
From:
override public func awakeFromFetch() {
refresh()
}
Which keeps the new accountVal property and bindings up to date. Since the previous Core Data attribute was "Transient" anyway there's no reason to use it when I can easily just use an #objc property instead. Much easier!

How do I update tableview cell when It had changed

When I scroll up&down then tableview cell has set overtimes so It affect lagging.
I want to update only when the data is updated.
Post.swift (It is model)
import Foundation
import Parse
class Post: PFObject, PFSubclassing {
#NSManaged var postBy: PFUser?
#NSManaged var postUser: String?
#NSManaged var postUserImg: PFFile?
#NSManaged var postText: String?
#NSManaged var postImg: PFFile?
#NSManaged var sell: NSNumber?
#NSManaged var commentPointer: PFObject?
#NSManaged var commentBy: String?
#NSManaged var comment: String?
#NSManaged var liked: NSArray?
#NSManaged var likeCount: NSNumber?
#NSManaged var mention: NSArray?
#NSManaged var hashtag: NSArray?
static func parseClassName() -> String {
return "Post"
}
override class func query() -> PFQuery<PFObject>? {
let query = PFQuery(className: Post.parseClassName())
return query
}
}
extension Post: FeedCellSupport {
var username:String?{
return postUser
}
var userImg:PFFile?{
return postUserImg
}
var commentText:String?{
guard let commentTxt = comment else {
return ""
}
return commentTxt
}
TableView.swift
protocol FeedCellSupport {
var postDate: String? { get }
var postId: String? { get }
var postObj: PFObject? { get }
var img: PFFile? { get }
var username:String?{ get }
var userImg:PFFile?{ get }
var commentText:String?{ get }
var commentFrom:String?{ get }
var postText: String? { get }
var likes: Int? { get }
var isLiked: Bool? { get }
var isSell: Bool? { get }
var hashtags: NSArray? { get }
var mentions: NSArray? { get }
}
func fetchObjects() {
let postQuery = Post.query()?
.whereKeyExists("objectId")
.includeKeys(["postBy", "commentPointer", "commentPointer.commentBy", "commentBy"])
.order(byDescending: "createdAt")
as! PFQuery<Post>
postQuery.limit = self.page
postQuery.cachePolicy = .networkElseCache
postQuery.findObjectsInBackground { (object:[Post]?, error:Error?) in
if error == nil {
self.results = object!
}else {
print(error?.localizedDescription as Any)
}
self.tableView.reloadData()
self.refresher.endRefreshing()
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ShopDetailCell", for: indexPath) as! ShopDetailCell
if let object = results[indexPath.row] as? FeedCellSupport{
cell.postID = object.postObj!
cell.userNameLabel.text = object.username!
cell.userNameLabel.sizeToFit()
cell.descriptionLabel.text = object.postText!
cell.descriptionLabel.sizeToFit()
cell.commentByLabel.text = object.commentFrom!
cell.commentByLabel.sizeToFit()
cell.commentLabel.text = object.commentText!
cell.commentLabel.sizeToFit()
cell.delegate = self
}
return cell
}
How can I ensure that data is updated only when it changes?
What are your App functionalities? Your problem is associated with the way suitable to accomplish your task, that is: to update app contents.
So it is about business logic: when should the information be updated?
The solution to your problem is using user toggled events to refresh the contents or other possible solutions such as Application Delegate.
Except for these answers, the contents cannot update tableview automatically as your expectation.
Update
I considered this line of code is lagging:
if let object = results[indexPath.row] as? FeedCellSupport{
//other code
}
Because code inside these braces is dealing with data setting. You could try to mock up local data instead of this results array to say whether this is the problem.

How to execute a fetchRequest count for each object from array?

I have 2 Entities:
Attendace:
import Foundation
import CoreData
extension Attendance {
#NSManaged var date: NSDate?
#NSManaged var id: NSNumber?
#NSManaged var id_consultant: String?
#NSManaged var id_store: NSNumber?
#NSManaged var name: String?
#NSManaged var status: String?
}
and Product :
import Foundation
import CoreData
extension Product {
#NSManaged var id: String?
#NSManaged var name: String?
#NSManaged var preco: String?
#NSManaged var attendance: Attendance?
}
I'm fetching all Attendances and need to execute a fetch to count how many products are there in a Attendance:
There's my method to fetch the Attendances. How could I get the count of products with the Attendance ID?
func fetchAttendances() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Attendance")
let attendancePredicate = NSPredicate(format: "id_store == \(Int(Helper.userDefaults().objectForKey(ConstantHelper.kIdStore)! as! NSNumber))")
fetchRequest.predicate = attendancePredicate
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
myAttendances = results as! [NSManagedObject]
self.collectionAttendances.reloadData()
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Assuming that you have set up your data model so that Attendance and Product have a one-to-many relationship...
Attendance <---->> Product
... you can leverage the map syntax to accomplish this in a very succinct way:
let countArray = attendanceArray.map { ($0.id, $.products?.count ?? 0) }
This will return an array of tuples with the id and the count of products.

CoreData and Swift: contents gets swapped

I am new to swift and have a problem with CoreData: I can save and load to and from my CoreData store. But when I load the saved data from CoreData the data has been rearranged. I don't want this to happen. How do I solve this?
My code is this:
Meetings.swift
import Foundation
import CoreData
class Meetings: NSManagedObject {
#NSManaged var meetingTimeLeft: NSNumber
#NSManaged var title: String
#NSManaged var date: NSDate
#NSManaged var timeFrom: NSDate
#NSManaged var timeTo: NSDate
#NSManaged var timeFromActual: NSDate
#NSManaged var timeToActual: NSDate
#NSManaged var location: String
#NSManaged var locationRoom: String
#NSManaged var meetingGoals: String
#NSManaged var purpose: String
#NSManaged var averageHourlyCost: NSNumber
#NSManaged var completed: NSNumber
#NSManaged var durationActual: NSNumber
#NSManaged var durationPlanned: NSNumber
#NSManaged var persons: NSSet
#NSManaged var agendas: NSSet
#NSManaged var minutes: NSSet
#NSManaged var relationship: NSManagedObject
#NSManaged var startSetting: StartSetting?
}
extension Meetings {
func addPer(value: Person) {
self.mutableSetValueForKey("persons").addObject(value)
}
func removePer(value: Person) {
self.mutableSetValueForKey("persons").removeObject(Person)
//self.mutableSetValueForKey("persons").addObject(value)
}
func getPer() -> [Person] {
var persons: [Person]
persons = self.persons.allObjects as! [Person]
return persons
}
func addAgenda(value: AgendaItem) {
self.mutableSetValueForKey("agendas").addObject(value)
}
func removeAgenda(value: AgendaItem) {
self.mutableSetValueForKey("agendas").removeObject(AgendaItem)
//self.mutableSetValueForKey("persons").addObject(value)
}
func getAgenda() -> [AgendaItem] {
var agendas: [AgendaItem]
agendas = self.agendas.allObjects as! [AgendaItem]
return agendas
}
func getAgendaItem(i: Int) -> AgendaItem {
var agendas: [AgendaItem]
agendas = self.agendas.allObjects as! [AgendaItem]
let agendaItem = agendas[i]
return agendaItem
}
}
person.swift
import Foundation
import CoreData
class Person: NSManagedObject {
#NSManaged var name: String
#NSManaged var email: String
#NSManaged var phone: NSNumber
#NSManaged var title: String
#NSManaged var company: String
#NSManaged var photo: NSData
#NSManaged var meeting: Meetings
}
AgendaItem.swift
import Foundation
import CoreData
class AgendaItem: NSManagedObject {
#NSManaged var agendaItemTitle: String
#NSManaged var presenter: String
#NSManaged var durationPlanned: NSNumber
#NSManaged var durationActual: NSNumber
#NSManaged var filePresentation: NSData
#NSManaged var fileSupporting: NSData
#NSManaged var agendaTimeStart: NSDate
#NSManaged var meeting: Meetings
}
when saving i do like this:
internal var meetingsModels = [Meetings]()
public let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
managedObjectContext?.deleteObject(meetingsModels[meetingsIndexPassed.row]) meetingsModels.removeAtIndex(meetingsIndexPassed.row)
let entityDescription = NSEntityDescription.entityForName("Meetings", inManagedObjectContext: managedObjectContext!)
let entityDescription2 = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext!)
let entityDescription3 = NSEntityDescription.entityForName("AgendaItem", inManagedObjectContext: managedObjectContext!)
let meetings = Meetings(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext)
meetings.title = meetingTitle_txt.text!
meetings.date = lDate
meetings.timeFrom = lStartTime
meetings.timeTo = lEndTime
meetings.location = address_txt.text!
meetings.purpose = details[0]
meetings.meetingGoals = details[1]
meetings.locationRoom = details[2]
meetings.durationPlanned = meetingsEditPassed.durationPlanned
meetings.completed = false
for var i = 0; i < personsEdit.count; i++ {
let person = Person(entity: entityDescription2!, insertIntoManagedObjectContext: managedObjectContext)
person.name = personsEdit[i].name
person.email = personsEdit[i].email
person.title = personsEdit[i].title
person.company = personsEdit[i].company
person.phone = personsEdit[i].phone
meetings.addPer(person)
}
for var i = 0; i < agendaEdit.count; i++ {
let agenda = AgendaItem(entity: entityDescription3!, insertIntoManagedObjectContext: managedObjectContext)
agenda.agendaItemTitle = agendaEdit[i].agendaItemTitle
//print(agendaEdit[i].agendaItemTitle)
agenda.presenter = agendaEdit[i].presenter
agenda.durationPlanned = agendaEdit[i].durationPlanned
meetings.addAgenda(agenda)
}
do {
try managedObjectContext?.save()
} catch let error1 as NSError {
print("\(error1)")
}
meetingsModels.append(meetings)
when loading i do this:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"Meetings")
//fetchRequest.sortDescriptors = nil
//3
let fetchedResults: [Meetings]
do {
try
fetchedResults = (managedContext.executeFetchRequest(fetchRequest) as? [Meetings])!
if let results: [Meetings] = fetchedResults {
var temp = [Meetings]()
var temp2 = [Meetings]()
for tmp: Meetings in results {
temp.append(tmp)
if tmp.completed.boolValue {
temp2.append(tmp)
}else {
}
}
meetingsModels = temp
meetingsModels2 = temp2
} else {
}
} catch let error1 as NSError {
print("could not fetch meetings: \(error1), \(error1.userInfo)")
}
}
i hope that some of you can help me.
Your meetings data is being "rearranged" just because your Meetings don't belong to any ordered relationship. I'm not able to run your code on my side. However, I can recommend you one of the following:
Use ordered relations any time you want to make sure the order of
data is preserved any time you fetch it.
Use the
sortDescriptors property on your fetch requests. When you
create one, you can add a sort descriptor to it in order to
arrange data.