How to fetch NSSet from Core Data in Swift - ios

I have a Person class and a Brand class that are a relationship in Core Data. I know how to fetch the entire Person class (NSManagedObject), but how do I drill down to only fetch the brand associated with the person?
import Foundation
import CoreData
class Person: NSManagedObject {
#NSManaged var name: String
#NSManaged var brands: NSSet
func addBrandsObject(value: Brand) {
self.mutableSetValueForKey("brands").addObject(value)
}
}
import Foundation
import CoreData
class Brand: NSManagedObject {
#NSManaged var name: String
#NSManaged var people: NSSet
}
Viewcontroller:
![import UIKit
import CoreData
class BrandsTableTableViewController: UITableViewController {
var brands = \[NSManagedObject\]()
var selectedPerson: Person?
var selectedBrand: Brand?
//Fetch Core Data
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.fetchCoreData()
}
//Helper Function to Fetch Core Data
func fetchCoreData() {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"Person")
//3
var error: NSError?
let fetchedResults =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as? \[NSManagedObject\]
if let results = fetchedResults {
////what here?
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}][1]

Since you already have the person instance, just access the relationship:
for person in results {
let brandSet = person.brands
}
No fetch required.
This is assuming of course that your relationship from Person to Brand is called brands.
There will also be some casting to go around, can't have swift without casting...

You need to tell it that what you are fetching is a "Person" object and then you can iterate through brands.
//Helper Function to Fetch Core Data
func fetchCoreData() {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"Person")
//3
var error: NSError?
var people =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as! [Person]
// Get all brands from all people
for (var x=0; x<people.count; x++) {
let brands: NSArray = people[x].brands.allObjects
for brand in brands {
println(brand.name)
}
}
}

Related

swift 3.1 How to sum async fetch properties

I cannot mace a count of a single property in an asynchronous fetch, I'd like to summ all expenseAmount for given async fetch but cannot apply for in pattern
my entity:
extension Expense {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Expense> {
return NSFetchRequest<Expense>(entityName: "Expense");
}
#NSManaged public var expenseAmount: Double
#NSManaged public var expenseDate: NSDate?
#NSManaged public var expenseOwner: String?
#NSManaged public var expenseTag: String?
}
in my view controller I call this func in my viewDidLoad, how could I select and summ the expenseAmount values for all fetched entities?
func makeAsyncFetch() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
managedContext = appDelegate.persistentContainer.viewContext
// MARK: - async fetch request 2
let expenseFetch = NSFetchRequest<Expense>(entityName: kExpenseEntityName)
asyncFetchRequest = NSAsynchronousFetchRequest<Expense>(fetchRequest: expenseFetch) {
[unowned self] (result: NSAsynchronousFetchResult) in
guard let Expenses = result.finalResult else {
return
}
self.asyncExpensesArray = Expenses
self.expenseTableView.reloadData()
// self.testPrintForMyArray(arrayToCheck: self.asyncExpensesArray)
// self.batchUpdate()
}
// MARK: - async fetch request 3
do {
try managedContext.execute(asyncFetchRequest)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Map the Expenses array to the expenseAmount values and sum them up.
let sum = Expenses.map({$0.expenseAmount}).reduce(0, {$0 + $1})
PS: According to the Swift 3 naming philosophy I recommend to name the Expense properties just amount, date, owner and tag and remove the redundant parts since it's clear that the properties belong to Expense .

Core data Relationship in swift

I am working on iPhone application where I need to implement one to many relationship from one entity to another entity.I have export NSManagedObject subclass from coredata database but could not find relation accessors in core data model file like Objective-C.
Although I'm able to set data in relationship NSSet but this only persist while iPhone app is running. Once I kill and restart the application I didn't get entity relationship for in fetch request from core data.
I am not sure what I am doing wrong. It will be great if anyone can tell me how to set data in NSSet relationship object. Any sample example will be a great help
Here is my core data model files. One folder can content multiple content as folder detail
extension FolderContent {
#NSManaged var contentID: NSNumber?
#NSManaged var contentTitle: String?
#NSManaged var contentType: String?
#NSManaged var publishDate: String?
#NSManaged var folderList: NSSet?
}
extension FolderList {
#NSManaged var folderID: NSNumber?
#NSManaged var folderName: String?
#NSManaged var folderDetail: NSSet?
}
func updateFolderList()
{
// Initialize Fetch Request
let fetchRequest = NSFetchRequest()
// Create Entity Description
let entityDescription = NSEntityDescription.entityForName(FOLDER_LIST, inManagedObjectContext: self.managedObjectContext)
// Configure Fetch Request
fetchRequest.entity = entityDescription
do {
let result = try self.managedObjectContext.executeFetchRequest(fetchRequest).last as! FolderList
let content = result.mutableSetValueForKey("folderDetail")
content.addObject(self.getContent())
var folderContent:FolderContent = result.folderDetail?.allObjects.first as! FolderContent
print(folderContent.contentTitle)
self.save()
print(result)
} catch {
let fetchError = error as NSError
print(fetchError)
}
}
func getContent()->FolderContent
{
let folderContent = NSEntityDescription.insertNewObjectForEntityForName(FOLDER_CONTENT, inManagedObjectContext: self.managedObjectContext) as! FolderContent
folderContent.contentID = 1
folderContent.contentTitle = "Sandeep"
folderContent.contentType = "Product"
return folderContent
}
If the relationship of FolderContent and FolderList is defined as
A FolderContent have many FolderList(s)
A FolderList only belongs to a FolderContent
FolderContent
extension FolderContent {
#NSManaged var contentID: NSNumber?
#NSManaged var contentTitle: String?
#NSManaged var contentType: String?
#NSManaged var publishDate: String?
#NSManaged var folderList: Set<FolderList>?
}
FolderList
extension FolderList {
#NSManaged var folderID: NSNumber?
#NSManaged var folderName: String?
#NSManaged var folderDetail: FolderContent?
}
Let say you want to persist the record and its relationship
func persistRecords() {
// Insert the new records
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let folderContentEntity = NSEntityDescription.entityForName("FolderContent", inManagedObjectContext: managedContext)
let folderListEntity = NSEntityDescription.entityForName("FolderList", inManagedObjectContext: managedContext)
//Create FolderContent record
let folderContentObject = FolderContent(entity: folderContentEntity!, insertIntoManagedObjectContext: managedContext)
folderContentObject.setValue(CONTENTID, forKeyPath: "contentID")
...
//Create FolderList record
let folderListObject = FolderList(entity: folderListEntity!, insertIntoManagedObjectContext: managedContext)
folderListObject.setValue(FOLDERID, forKeyPath: "folderID")
...
//Set relationship here
folderListObject.folderDetail = folderContentObject
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
I am guessing you did something like folder.folderDetail.addObject. With core data that won't work because core data behind the scenes is doing lots of things to maintain graph integrity. You have to use mutableSetValueForKey to get the set and have core data work its magic.

App Delegate - Load Core Data Swift

My app crashes every time using the abort function- core data. It crashes because of this code. What is wrong with it?
import UIKit
import CoreData
class MyWordsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var myList: Array<AnyObject> = []
override func viewDidLoad() {
super.viewDidLoad()
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDel.managedObjectContext
let freq = NSFetchRequest(entityName: "List")
do {
try myList = context.executeFetchRequest(freq)
} catch {
print("error")
}
tableView.reloadData()
Delegate for tableview are not added in your code.
Add these in your view controller
class MyWordsTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
Add this code in your viewDidLoad
self.Tablename.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
Tablename.dataSource = self
Tablename.delegate = self
searchBar.delegate = self
For core data try the following code
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
var fetchRequest = NSFetchRequest(entityName: "List")
if let fetchResults = appDel.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] {
if fetchResults.count != 0{
println(fetchResults)
}
}
Try this, worked for me (swift 2 Xcode 7 beta 5): (I did changes to fit your code)
import UIKit
import CoreData
var myList: Array<AnyObject> = []
class MyWordsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate
{
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewDidAppear(animated:Bool)
{
//reference to app delegate
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
//reference NSManaged object context
let context: NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "List")
do
{
try myList = context.executeFetchRequest(freq)
NSLog("Number of rows (App): \(myList.count)")
} catch _ { NSLog("That went badly...") }
tableView.reloadData()
}
}

How to delete several different data from Core Data in Swift?

I have Core Data with five objects. It's four String and one NSData (UIImage). I save them in Core Data. Then load in UIViewController and I want to delete them from Core Data and I got different errors. I tried different methods but it doesn't helped me. How do I delete these data?
var name: String!
var text: String!
var image: UIImage!
var url: String!
var data: String!
func deleteAll() {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var managedObjectContext: NSManagedObjectContext = appDel.managedObjectContext!
var coreDataName: NSManagedObject = (name as AnyObject?) as! NSManagedObject
var coreDataImage: NSManagedObject = (image as AnyObject?) as! NSManagedObject
var coreDataText: NSManagedObject = (text as AnyObject?) as! NSManagedObject
var coreDataData: NSManagedObject = (data as AnyObject?) as! NSManagedObject
var coreDataURL: NSManagedObject = (url as AnyObject?) as! NSManagedObject
managedObjectContext.deleteObject(coreDataName)
managedObjectContext.deleteObject(coreDataImage)
managedObjectContext.deleteObject(coreDataText)
managedObjectContext.deleteObject(coreDataData)
managedObjectContext.deleteObject(coreDataURL)
managedObjectContext.save(nil)
buttonDelete.enabled = false
buttonShare.enabled = false
}
}
My Core Data file
import Foundation
import CoreData
#objc(News)
class News: NSManagedObject {
#NSManaged var dateNewsCoreDataString: String
#NSManaged var imageNewsCoreData: NSData // NSData
#NSManaged var nameNewsCoreData: String
#NSManaged var textNewsCoreData: String
#NSManaged var urlNewsCoreData: String
}
I changed my code and it work for me.
var detailObject: AnyObject? // It's data from FavoriteTableViewController
func deleteAll() {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var managedObjectContext: NSManagedObjectContext = appDel.managedObjectContext!
var dataDelete = detailObject as! NSManagedObject
managedObjectContext.deleteObject(dataDelete)
managedObjectContext.save(nil)
managedObjectContext.save(nil)
buttonDelete.enabled = false
buttonShare.enabled = false
}

How to overwrite Core Data attribute in Swift

I'm trying to update an attribute in Core Data and then display it. However, when I tell the program to display it, it displays the original value.
Based off the code below, username is set to a String. I know 100% that username is saved into Core Data. However, when I try to update it, it saves to Core Data, but prints out the old value. How can I print out only the "newest" value?
import UIKit
import CoreData
class NameSettings: UIViewController {
#IBOutlet var nameText: UITextField!
var userID: String!
var username: String!
override func viewDidLoad() {
super.viewDidLoad()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
var res = results [0] as NSManagedObject
userID = res.valueForKey("userID") as String
username = res.valueForKey("username") as String
println(username)
nameText.text = username
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func saveTapped(sender: AnyObject) {
//println(userID)
var query = PFQuery(className:"_User")
query.getObjectInBackgroundWithId(userID) {
(update1: PFObject!, error: NSError!) -> Void in
if error == nil {
update1["username"] = self.nameText.text
update1.saveEventually()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var updateUser = NSEntityDescription.insertNewObjectForEntityForName("Users", inManagedObjectContext: context) as NSManagedObject
updateUser.setValue(self.nameText.text, forKey: "username")
context.save(nil)
//println(self.nameText.text)
self.navigationController?.popToRootViewControllerAnimated(true)
}
}
}
}
NOTE: All the println's are just for debugging.
As your code stands now, you're not overwriting any NSManagedObject; you're inserting a new one, i.e. insertNewObjectForEntityForName.
Instead, what you can do is declare the NSManagedObject you want to save and the NSManagedObjectContext you want to save to as global variables; then simply set a new value for the NSManagedObject's relevant key before saving to the NSManagedObjectContext, ex:
var userID: String!
var username: String!
var res : NSManagedObject!
var context : NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
//...
context = appDel.managedObjectContext! // <-- Use global var
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
res = results [0] as NSManagedObject // <-- Use global var
//...
}
#IBAction func saveTapped(sender: AnyObject) {
//println(userID)
var query = PFQuery(className:"_User")
query.getObjectInBackgroundWithId(userID) {
(update1: PFObject!, error: NSError!) -> Void in
if error == nil {
update1["username"] = self.nameText.text
update1.saveEventually()
res.setValue(self.nameText.text, forKey: "username")
context.save(nil)
//println(self.nameText.text)
self.navigationController?.popToRootViewControllerAnimated(true)
}
}
}

Resources