I'm a little bit confused try to fetch relation data from coredata in swift
Person Entity
contains the name of person and Unique Id. The relation with Books is ONE to Many
For example
Person Entity:
idPerson = 25 - namePerson = John
idPerson = 26 - namePerson = Steve
Books Entity contains the title of books, Unique Id for the book and a relation ID with person (personBook). The relation with Person is ONE to ONE
For example
Books Entity:
idBook = 2543 - titleBook = title one - personBook = 25
idBook = 2544 - titleBook = title two - personBook = 25
idBook = 2545 - titleBook = title three - personBook = 26
here my data model screenshot: (no image because i have no reputation)
Person class
#objc(Person)
class Person: NSManagedObject {
#NSManaged var idPerson: String
#NSManaged var namePerson: String
#NSManaged var booksRel: NSSet
}
Books class
#objc(Books)
class Books: NSManagedObject {
#NSManaged var bookTitle: String
#NSManaged var idBook: String
#NSManaged var personBook: String
#NSManaged var personRel: Person
}
Fetch code
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let request = NSFetchRequest(entityName: "Books")
request.returnsObjectsAsFaults = false
request.fetchLimit = 30
////////////////////////////
// CODE TO JOIN Person entity WHERE personBook = idPerson
////////////////////////////
var results:NSArray = context.executeFetchRequest(request, error: nil)!
for temp in results {
var data = temp as Books
///////////////////////////////////////
//println(data.namePerson) ----> not working
///////////////////////////////////////
}
is possibile to fetch for every book the related namePerson based on namePerson = personBook ?
Thank you very much!
You don't need a property personBook for your Books entity.
Let's create a Person managedObject (using Swift 1.0):
let person = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: context) as Person
person.idPerson = 23
person.namePerson = "John"
var error: NSError?
if !context.save(&error) {
println("Unresolved error \(error), \(error!.userInfo)")
abort()
}
When you create a Books managedObject, you can link it to person like this:
let book = NSEntityDescription.insertNewObjectForEntityForName("Books", inManagedObjectContext: context) as Books
book.bookTitle = "My book Title"
book.idBook = 2547
book.personRel = person
var error: NSError?
if !context.save(&error) {
println("Unresolved error \(error), \(error!.userInfo)")
abort()
}
Now, when you want to make a fetch on Books, you can do like this:
let fetchRequest = NSFetchRequest(entityName: "Books")
var error: NSError?
var booksArray = context.executeFetchRequest(fetchRequest, error:&error)
if let error = error {
println("Unresolved error \(error), \(error.userInfo)")
abort()
}
for book in booksArray as [Books] {
let person = book.personRel as Person
println(person.namePerson)
println(person.idPerson)
}
If I have understood your question / data structure correctly, you will want to do something like:
let fetchRequest = NSFetchRequest(entityName: "Books")
let bookPersonPredicate = NSPredicate(format: "personRel.idPerson == %#", person.idPerson)
fetchRequest.predicate = bookPersonPredicate
Related
For example two models Person and Car. Person has many cars. My question is how to add car to already created Person. If I tray in AddNewCarView:
var person: Person
...
var newCar = Car(context: viewContext)
newCar.name = name
newCar.model = model
And now, what...?
newCar.person = person (gives newCar to all persons)
Or.
person.addToCars(newCar)
Is that something I have to add in predicate? In Car I have:
static func fetchCars() -> NSFetchRequest<Car> {
let request: NSFetchRequest<Car> = Car.fetchRequest()
reqest.predicate = NSPredicate(format: "", ) ..?
request.sortDescriptors = [NSSortDescriptor(keyPath: \Car.timestamp, ascending: true)]
return request
}
I have EmployeeExample and Deptt as entities.
EmployeeExample one to one relationship with Dept
Dept has more than one relationship with EmployeeExample
I want to save data through relationship. I have dept entity object, with that I want to save employeeexample entity
I achieved this, but I want to know whether it is the optimal way. Any optimal way? I would like to know how the relationship works.
My code :
import UIKit
import CoreData
class ViewController: UIViewController {
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
let appDelegate = UIApplication.shared.delegate as! AppDelegate
var empSet = NSSet()
var empS = Set<EmployeeExample>()
override func viewDidLoad() {
super.viewDidLoad()
var context:NSManagedObjectContext = (container?.viewContext)!
let dept = NSEntityDescription.insertNewObject(forEntityName: "Deptt", into: context) as! Deptt
let emp = NSEntityDescription.insertNewObject(forEntityName: "EmployeeExample", into: (container?.viewContext)!) as! EmployeeExample
emp.firstName = "YYYY"
emp.lastName = "HHHHHHH"
empS.insert(emp)
print("Count of Emp SSSS Set == \(empS.count)")
let emp1 = NSEntityDescription.insertNewObject(forEntityName: "EmployeeExample", into: (container?.viewContext)!) as! EmployeeExample
emp1.firstName = "RRRRR"
emp1.lastName = "YYYYY"
empS.insert(emp1)
empSet.addingObjects(from: empS)
dept.deptName = "CCC"
print("Count of Emp SSSS Set == \(empS.count)")
print("Count of Emp Set == \(empSet.count)")
dept.addToEmp(empSet)
do {
try appDelegate.saveContext()
print("Saved -------------")
}catch {}
}
}
Do I have to create an Employee instance each time?
Do I have to create an Employee instance each time?
Well, do you have a new employee each time? If you have new information, you need to create a new Employee record. If you're using existing information, you look up an existing Employee from your persistent store by using NSFetchRequest. You create new instances when you have new data to save. Whether you need to do that is something only you can answer. If you have new data, yes. Otherwise, no.
I've been chasing a bug for a while now and I can't figure it out. I have a class that takes a bunch of parsed data and then calls a method to create new core data "Article" object for each element created from the parsed data. I've shown how I declare the NSManagedObjectContext below.
You will also see the method
Article.createFLOArticleWithStructure(element, inManagedObjectContext: self.articleContext)
I placed this method in an extension to clean up the code. The method is show below.
import Foundation
class FLODataHandler : NSObject, FLOConnectionHandlerDelegate, FLOParserHandlerDelegate, TriathleteParserHandlerDelegate, VeloNewsParserHandlerDelegate, CyclingNewsParserHandlerDelegate, RoadBikeActionParserHandlerDelegate, IronmanParserHandlerDelegate
{
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
lazy var articleContext: NSManagedObjectContext = self.appDelegate.managedObjectContext!
func floParserHandlerDidFinishParsing(parserHandler : FLOParserHandler)
{
for element in self.floParserHandler!.XMLParsedDataArray!
{
// The pubDate, tilte and link and indicator have been added to the titleLinkArray. I will now add the data to a Core Data Entity
// in the Article+NewsFeedArticle class.
Article.createFLOArticleWithStructure(element, inManagedObjectContext: self.articleContext)
}
}
Extension Code
extension Article
{
class func createFLOArticleWithStructure(articleStructure: DateTitleLink, inManagedObjectContext context: NSManagedObjectContext) -> (Article)
{
// Core data is much simpler in Swift. I have not commented this code since I do not know if it's working yet.
var article = Article()
//var entity = NSEntityDescription("Article", inManagedObjectContext: context)
let fetchRequest = NSFetchRequest(entityName: "Article")
let predicate = NSPredicate(format: "feed == 'FLO Cycling' AND title == %#", articleStructure.title!)
let sortDescriptor = NSSortDescriptor(key: "pubDate", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
// Set up NSError
var fetchError : NSError?
// When you perform a fetch the returned object is an array of the Atricle Entities.
let fetchedObjects = context.executeFetchRequest(fetchRequest, error: &fetchError) as! [Article]
if fetchedObjects.count > 1
{
println("Error! in Article+NewFeedArticle.swift")
}
else if fetchedObjects.count == 0
{
article = NSEntityDescription.insertNewObjectForEntityForName("Article", inManagedObjectContext: context) as! Article
article.feed = "FLO Cycling"
article.pubDate = articleStructure.date!
article.title = articleStructure.title!
article.link = articleStructure.link!
article.theNewArticle = NSNumber(int: 1)
var error : NSError?
if(context.save(&error))
{
println(error!.localizedDescription)
}
}
else if fetchedObjects.count == 1
{
article = fetchedObjects[fetchedObjects.endIndex - 1]
}
return article
}
When I run the code I get stopped on the following line of the extension code and receive the following errors.
article = NSEntityDescription.insertNewObjectForEntityForName("Article", inManagedObjectContext: context) as! Article
CoreData: error: Failed to call designated initializer on
NSManagedObject class 'FLOCycling1_1_1.Article' CoreData: warning:
Unable to load class named 'Article' for entity 'Article'. Class not
found, using default NSManagedObject instead. Could not cast value of
type 'NSManagedObject_Article_' (0x7fe59c3515e0) to
'FLOCycling1_1_1.Article' (0x106139f70).
I've read online about using a prefix in the data model. I've added this to no avail. If you have any idea how I can fix this error I would appreciate the help.
ADDED****
Here is the Article.swift file on request.
import Foundation
import CoreData
#objc class Article: NSManagedObject
{
#NSManaged var feed: String
#NSManaged var link: String
#NSManaged var pubDate: NSDate
#NSManaged var theNewArticle: NSNumber
#NSManaged var title: String
}
Take care,
Jon
The issue had to do with my declaration of Article in this line here.
var article = Article()
In the Swift version calling the line of code above allocates and initializes memory for the Article. In the Objective-C version of my code I called the following.
Article *article = nil;
While I am not sure why, allocating and initializing the Article is the issue. I found this post here about a similar error.
Failed to call designated initializer on NSManagedObject class 'ClassName'
To fix this I changed the code to
var article = Article?()
To be clear, I also changed the Article class to ProjectName.Article.
I hope this helps someone else.
Take care,
Jon
I'm new to CoreData, have read a few tutorials but have come up empty-handed. Most tutorials have centered around fetching from CoreData to populate a tableview, which is not what I'm doing at the moment.
Here's how I'm setting the data in CoreData. All types are Double except for date which is an NSDate
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
let managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Meditation", inManagedObjectContext: managedObjectContext!)
let meditation = NSManagedObject(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
meditation.setValue(settings.minutes, forKey: "length")
meditation.setValue(settings.warmup, forKey: "warmup")
meditation.setValue(settings.cooldown, forKey: "cooldown")
meditation.setValue(NSDate(), forKey: "date")
// fetch stuff from CoreData
var request = NSFetchRequest(entityName: "Meditation")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
for res in results {
println(res)
}
Here's what I'm trying to do to get the results, but I'm not able to access things like .minutes, .date, etc. I know I'm also not properly getting the last item either, I was just trying to print out attributes on the object first.
I'd love help on how to fetch only the most recent object as well as show it's attributes
Thanks!
First, create a "Meditation.swift" file in Xcode with "Editor -> Create NSManagedObject
Subclass ...". The generated file should look like
import Foundation
import CoreData
class Meditation: NSManagedObject {
#NSManaged var length: NSNumber
#NSManaged var warmup: NSNumber
#NSManaged var cooldown: NSNumber
#NSManaged var date: NSDate
}
Now you can use the properties directly instead of Key-Value Coding
and create the object as
let meditation = NSEntityDescription.insertNewObjectForEntityForName("Meditation", inManagedObjectContext: managedObjectContext) as Meditation
meditation.length = ...
meditation.warmup = ...
meditation.cooldown = ...
meditation.date = NSDate()
var error : NSError?
if !managedObjectContext.save(&error) {
println("save failed: \(error?.localizedDescription)")
}
When fetching the object, cast the result of
executeFetchRequest() to [Meditation]:
let request = NSFetchRequest(entityName: "Meditation")
var error : NSError?
let result = managedObjectContext.executeFetchRequest(request, error: &error)
if let objects = result as? [Meditation] {
for meditation in objects {
println(meditation.length)
println(meditation.date)
// ...
}
} else {
println("fetch failed: \(error?.localizedDescription)")
}
Finally, to fetch only the latest object, add a sort descriptor to
sort the results by date in descending order, and limit the number of results to one:
let request = NSFetchRequest(entityName: "Meditation")
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
request.fetchLimit = 1
// ...
Then the objects array contains at most one object, which is the most recent one.
I am trying to fetch some data from Core Data and have run into a slight problem. I can fetch the data with no problem. The moment I try to grab a specific piece of data (i.e. data.fooBar), it throws up an error:
"'AnyObject' does not have a member name 'fooBar'
If I println(data) it will show that fooBar does exist with data stored in it.
I am not really sure why it is doing this. I have tried to search for an answer and tried a bunch of different things but none have seemed to work. Any help would be great. Thanks. :)
var results : Array<AnyObject> = []
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
//get the data for that storedItem
var appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
var context:NSManagedObjectContext = appDel.managedObjectContext!
let req = NSFetchRequest(entityName: "storedItems")
let name:String = results[indexPath.row].name
req.predicate = NSPredicate(format: "name == %#", name)
req.returnsObjectsAsFaults = false
var tapResults = context.executeFetchRequest(req, error: nil)!
for item in tapResults {
println(item) //works, shows all data correctly(including subText)
println(item.name) //works, the only one that does for some reason???
println(item.subText) //Error 'AnyObject' does not have a member name 'subText'
}
Here is the result for: println(item)
println(item) <NSManagedObject: 0x7f04be60> (entity: storedItems; id: 0x7f041de0 <x-coredata://DD4F8E68-2234-46B5-B1D8-AE2F75245C63/storedItems/p1> ; data: {
alarmSound = default;
isDefault = 0;
name = "test";
sliderHours = 0;
sliderMinutes = 0;
sliderSeconds = 0;
subText = "00:00:00";
UPDATE: Based on discussion over vacawama answer (Thank you Aaron). For correct solution please see the answer I accepted.
my itemObj class
#objc(itemObj)
class itemObj: NSManagedObject {
#NSManaged var name:String!
#NSManaged var sliderHours:NSNumber
#NSManaged var sliderMinutes:NSNumber
#NSManaged var sliderSeconds:NSNumber
#NSManaged var subText:String!
#NSManaged var alarmSound:String!
#NSManaged var isDefault:NSNumber
}
my AddItem VC:
var tResults = (context.executeFetchRequest(req, error: nil))
for item in tResults as [itemObj!] {
println(item.name)
println(item.subText)
}
executeFetchRequest returns an optional array of AnyObject. You shouldn't force-unwrap it (this can cause a crash). So optionally unwrap it and do an optional cast (as?) to make sure the type is correct:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let req = NSFetchRequest(entityName: "storedItems")
let name:String = results[indexPath.row].name
req.predicate = NSPredicate(format: "name == %#", name)
req.returnsObjectsAsFaults = false
let tapResults = context.executeFetchRequest(req, error: nil)
if let presentResults = tapResults {
if let castedResults = presentResults as? [MyManagedObjectSubclass] {
for item in castedResults {
println(item)
println(item.name)
println(item.subText)
}
}
}
}
I also changed all of your vars to lets since they don't need to be mutable.
Just replace MyManagedObjectSubclass with whatever your NSManagedObject subclass is.