One-to-Many Relationship in Swift Core Data - swift

I'm building a journal app where you create a FocusArea object, which then contains 30 journal Entry objects.
So I created a one-to-many relationship in my data model.
Then I implemented two NSManagedObject Classes:
#objc(FocusArea)
class FocusArea: NSManagedObject {
#NSManaged var focusName: String
#NSManaged var focusStart: NSDate
#NSManaged var focusEnd: NSDate
#NSManaged var completeFlag: Bool
//#NSManaged var entries: NSSet
var entries: NSMutableOrderedSet {
return self.mutableOrderedSetValueForKey("entries")
}
}
#objc(Entry)
class Entry: NSManagedObject {
#NSManaged var entryJournal: String
#NSManaged var entryDate: NSDate
#NSManaged var completeFlag: Bool
#NSManaged var entryStatus: Bool
#NSManaged var focus: FocusArea
}
I'm able to add a FocusArea with no problems, but when I try to create 30 Entry objects and store in FocusArea.entries, everything keeps crashing.
What's the correct way to add multiple Entry objects to the FocusArea object?
Am I way off here?
#IBAction func saveFocusArea(sender: AnyObject) {
if txtFocusName.text != nil {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext!
//create new focus area
let entFocus = NSEntityDescription.entityForName("FocusArea", inManagedObjectContext: context)
let newFocus = FocusArea(entity:entFocus!, insertIntoManagedObjectContext: context)
newFocus.focusName = txtFocusName.text!
newFocus.focusStart = NSDate()
newFocus.focusEnd = NSDate().dateByAddingTimeInterval(60*60*24*30)
newFocus.completeFlag = false
//initialize 30 new entries into core data
let entEntry = NSEntityDescription.entityForName("Entry", inManagedObjectContext: context)
for var i = 0; i < 30; i++ {
let newEntry = Entry(entity:entEntry!, insertIntoManagedObjectContext: context)
let c = Double(i)
newEntry.entryDate = NSDate().dateByAddingTimeInterval(60*60*24*c)
newEntry.entryJournal = ""
newEntry.entryStatus = false
newEntry.completeFlag = false
//THIS IS THE PROBLEM AREA
newFocus.entries.append(newEntry)
}
do {
try context.save()
} catch {
print("There's a problem!")
}
}
}

I figured it out. All I had to do was:
newEntry.focus = newFocus.
So instead of setting the relationship between the parent to the child, set it from the child to the parent.

Related

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.

Core Data Fetch Relationship not working

I have a problem with fetching data from relationships.
I have a survey and i want to save the answers, the userIds and the results to core data and fetch the data at the next start of the app.
They are in arrays.
Each of it will be turned to a NSManagedObject "Wert", into the attribute "valueInt" if it is a result and "valueString" if it is an answer or an userId.
extension Wert {
#NSManaged var valueInt: NSNumber?
#NSManaged var valueString: String?
}
Afterwards it will be saved on the NSManagedObject "Message", as a NSSet on answers, results or userIds.
extension Message {
#NSManaged var absenderId: String?
#NSManaged var absenderName: String?
#NSManaged var datum: NSDate?
#NSManaged var gruppenId: String?
#NSManaged var image: NSData?
#NSManaged var latitude: NSNumber?
#NSManaged var longitude: NSNumber?
#NSManaged var messageId: String?
#NSManaged var question: String?
#NSManaged var sound: NSData?
#NSManaged var text: String?
#NSManaged var answers: NSSet?
#NSManaged var results: NSSet?
#NSManaged var userIDs: NSSet?
}
I think that this is working, because after the "addObjectsFromArray" AnswersSet contains some values.
func saveCoreData(AbsenderName: String, AbsenderID: String, Text: String?, Image: NSData?, Datum: NSDate, Latitude: Double?, Longitude: Double?, MessageId: String, Sound: NSData?, question: String?, answers : [String]?, results : [Int]?, userIDs: [String]?) {
let newMessage = NSEntityDescription.insertNewObjectForEntityForName("Message", inManagedObjectContext: context) as NSManagedObject
newMessage.setValue(AbsenderID, forKey: "absenderId")
newMessage.setValue(AbsenderName, forKey: "absenderName")
newMessage.setValue(Text, forKey: "text")
newMessage.setValue(Image, forKey: "image")
newMessage.setValue(Latitude, forKey: "latitude")
newMessage.setValue(Longitude, forKey: "longitude")
newMessage.setValue(Datum, forKey: "datum")
newMessage.setValue(GroupId, forKey: "gruppenId")
newMessage.setValue(MessageId, forKey: "messageId")
newMessage.setValue(Sound, forKey: "sound")
if question != nil && answers != nil && results != nil && userIDs != nil {
newMessage.setValue(question, forKey: "question")
var AnswersArray = [NSManagedObject]()
var ResultsArray = [NSManagedObject]()
var userIDsArray = [NSManagedObject]()
for var index = 0; index < answers?.count ; ++index {
let newWert = NSEntityDescription.insertNewObjectForEntityForName("Wert", inManagedObjectContext: context) as NSManagedObject
newWert.setValue(answers![index], forKey: "valueString")
AnswersArray.append(newWert)
}
for var index = 0; index < results?.count ; ++index {
let newWert = NSEntityDescription.insertNewObjectForEntityForName("Wert", inManagedObjectContext: context) as NSManagedObject
newWert.setValue(results![index], forKey: "valueInt")
ResultsArray.append(newWert)
}
for var index = 0; index < userIDs?.count ; ++index {
let newWert = NSEntityDescription.insertNewObjectForEntityForName("Wert", inManagedObjectContext: context) as NSManagedObject
newWert.setValue(userIDs![index], forKey: "valueString")
userIDsArray.append(newWert)
}
let answersSet = newMessage.mutableSetValueForKey("answers")
let resultsSet = newMessage.mutableSetValueForKey("results")
let userIdsSet = newMessage.mutableSetValueForKey("userIDs")
answersSet.addObjectsFromArray(AnswersArray)
resultsSet.addObjectsFromArray(ResultsArray)
userIdsSet.addObjectsFromArray(userIDsArray)
}
do {
try context.save()
}
catch _ {
print("Error")
}
}
But when i try to fetch the saved values with mutableSetValueForKey(), they contain 0 objects. Everything else is working.
func loadCoreData() -> Int {
var x : [AnyObject] = [AnyObject]()
let request = NSFetchRequest(entityName: "Message")
request.resultType = NSFetchRequestResultType.DictionaryResultType
request.predicate = NSPredicate(format: "gruppenId = %#", GroupId)
let sort1 = NSSortDescriptor(key: "datum", ascending: true)
request.sortDescriptors = [sort1]
do {
x = try context.executeFetchRequest(request)
for (var i = 0 ; i < x.count; ++i ) {
let Absender = x[i].valueForKey("absenderName") as! String
let AbsenderID = x[i].valueForKey("absenderId") as! String
let Text : String? = x[i].valueForKey("text") as? String
let Image : NSData? = x[i].valueForKey("image") as? NSData
let Sound : NSData? = x[i].valueForKey("sound") as? NSData
let Date : NSDate = x[i].valueForKey("datum") as! NSDate
let GruppenID : String = x[i].valueForKey("gruppenId") as! String
let MessageID : String = x[i].valueForKey("messageId") as! String
let longitude : Double? = x[i].valueForKey("longitude") as? Double
let latitude : Double? = x[i].valueForKey("latitude") as? Double
let question : String? = x[i].valueForKey("question") as? String
let answers = x[i].mutableSetValueForKey("answers") as? NSMutableSet
let results = x[i].mutableSetValueForKey("results") as? NSMutableSet
let userIds = x[i].mutableSetValueForKey("userIDs") as? NSMutableSet
}
}
}
It seems that the answers, results etc. are one-to-many relationships. In this case, it is always safer (and more concise) to simply set the to-one relationship.
Thus, rather than maintaining a clumsy array and dealing with mutableSetValueForKey, you could simply use the inverse relationship:
newWert.message = newMessage
NB: Please adopt the convention of using lowerCase variable names to avoid confusion with class names.
NB2: I strongly advise using NSManagedObject subclasses and using dot.notation to set and get values. With one stroke, all the variables you define in your many lines of code above would become utterly superfluous.

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.

Relationship with Swift

I have a code:
extension Person {
#NSManaged var name: String?
#NSManaged var personDevice: NSSet?
}
extension Device {
#NSManaged var deviceName: String?
#NSManaged var device: Person?
}
class Person: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
func addNewDevice(device:Device) {
let newDevice = self.mutableSetValueForKey("personDevice")
newDevice.addObject(device)
}
}
and call this:
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext)
let contact = Person(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext)
let entityDevice = NSEntityDescription.entityForName("Device", inManagedObjectContext: managedObjectContext)
let device = Device(entity: entityDevice!, insertIntoManagedObjectContext: managedObjectContext)
contact.name = "Test"
device.deviceName = "3310"
contact.addNewDevice(Device())
But I get error.
"CoreData: error: Failed to call designated initializer on
NSManagedObject class 'Test.Device' "
How fix it, please?

Swift core data saving to multiple entity's

In my view I have UITextfields for all except note which is a UITextView. When I hit save it dose save all the data but dose not link the note to the Teas entity.
#IBAction func addTea(sender: AnyObject) {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Teas", inManagedObjectContext: context)
var newItem = dataModel(entity: en!, insertIntoManagedObjectContext: context)
newItem.teaname = teaName.text
newItem.teatype = teaType.text
newItem.amount = qty.text
newItem.temp = temp.text
newItem.time = time.text
let en1 = NSEntityDescription.entityForName("Notes", inManagedObjectContext: context)
let newNote = dataNote(entity: en1!, insertIntoManagedObjectContext: context)
newNote.note = note.text
println(note.text)
context.save(nil)
self.navigationController?.popViewControllerAnimated(true)
}
dataModel.swift
#objc(dataModel)
class dataModel: NSManagedObject {
#NSManaged var amount: String
#NSManaged var teaname: String
#NSManaged var teatype: String
#NSManaged var temp: String
#NSManaged var time: String
#NSManaged var notes: dataNote
}
notes.swift
#objc(dataNote)
class dataNote: NSManagedObject {
#NSManaged var note: String
#NSManaged var teas: dataModel
}
I think after looking at a lot of other examples I need some thing like this.
#IBAction func addTea(sender: AnyObject) {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Teas", inManagedObjectContext: context)
var newItem = dataModel(entity: en!, insertIntoManagedObjectContext: context)
newItem.teaname = teaName.text
newItem.teatype = teaType.text
newItem.amount = qty.text
newItem.temp = temp.text
newItem.time = time.text
newItem.notesRel = noteAdd.text
But I get 'NSString' is not a subtype of 'dataNote'