I have a very beginner question.
First of all, i have an Entity(Person) with an Attribute(name).
I want to fetch the name attributes to one array to pick a randomElement from. The following code successfully returns data to separate arrays:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
request.returnsObjectsAsFaults = false
var myArray: [String]?
do {
let results = try context.fetch(request)
for result in results as! [NSManagedObject] {
if let username = result.value(forKey: "name") as? String {
myArray = [username]
print(myArray!)
}
}
}
catch {
print("not successful")
}
What can I use instead of 'FOR'? And how?
Thank you so much, and sorry for my soo beginner question.
You may cast to actual entity name
var myArray = [String]()
do {
let results = try context.fetch(request)
myArray = (results as! [Person]).compactMap { $0.name }
print(myArray)
}
catch {
print("not successful")
}
Related
I am reading data with following code from CoreData but instead of that can we read first attribute names "firstName", "lastName", "age" from CoreData into an array and read their values instead of writing all the names in code.
It is repeated work because they are written in DataModel as well.
loadData() {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
do {
let result = try context.fetch(fetchRequest)
dump(result)
for data in result as! [NSManagedObject] {
fNames = data.value(forKey: "firstName") as! String
lNames = data.value(forKey: "lastName") as! String
age = data.value(forKey: "age") as! Int
print("first \(fNames), last : \(lNames), last : \(age)")
}
} catch {
print("Could not load data: \(error.localizedDescription)")
}
}
Use the class that Xcode has generated for you that has the same name as the entity name
loadData() {
//Declare fetch request to hold the class you want to fetch
let fetchRequest = NSFetchRequest<Entity>(entityName: "Entity")
do {
let result = try context.fetch(fetchRequest)
dump(result)
for data in result {
// result is now [Entity] so you can access properties directly
// and without casting
let firstName = data.firstName
let lastName = data.lastName
let age = data.age
print("first \(firstName), last : \(lastName), age : \(age)")
}
} catch let error as NSError {
print("Could not load data: \(error.localizedDescription)")
}
}
Try this, access your entity name from NSManagedObject
e.g.
For AppDelegate.SharedInstance(), just declare this func in AppDelegate.swift
class func sharedInstance() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"CallHistory") //Here CallHistory is my entity name which i can access as NSManagedObject
let arr_callhistory = try AppDelegate.sharedInstance().persistentContainer.viewContext.fetch(fetchRequest) as! [CallHistory]
if arr_callhistory.count != 0
{
for callhistory_dict in arr_callhistory
{
let callStatus = callhistory_dict.callStatus
}
}
I have stored some Strings in CoreData (for example names of persons). Now I want to load these names into an array.
func loadData() -> Array<String> {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
var test = ""
var DataArray = [String]()
do {
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject] {
if let firstusername = result.value(forKey: "username") as? String {
test = firstusername
}
testArray.append(contentsOf: test)
}
}
} catch {
print("Roor")
}
print(type(of: test))
return testArray
}
I always get this error message: Instance method 'append(contentsOf:)' requires the types 'String' and 'String.Element' (aka 'Character') be equivalent
append(contentsOf: expects a sequence of items, you have to use just append(, and you should move the append line into the if let body
if let firstusername = result.value(forKey: "username") as? String {
testArray.append(firstusername)
}
or if you want to append an empty string if there is no name
testArray.append((result.value(forKey: "username") as? String) ?? "")
Nevertheless your method contains a lot of redundant code, this is sufficient
func loadData() throws -> Array<String> {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<Users>(entityName: "Users")
request.returnsObjectsAsFaults = false
let results = try context.fetch(request)
return results.compactMap{ $0.username }
}
It returns the array of names or hands over a potential error.
I was wondering why I can't add my data from Core Data to my tableview. It was first added and stored but when the app is reloaded the data is gone so I need to reload it but I can't seem to add the data to my tableview?
Here is the code
var titlename: [NSManagedObject] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let manageContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Items")
fetchRequest.returnsObjectsAsFaults = false
do {
let results = try manageContext.fetch(fetchRequest)
for result in results as! [NSManagedObject] {
if let theName = result.value(forKey: "name") as? String {
titlename.append(theName)
}
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
tableView.reloadData()
}
You may want to change titleName type to
var titlename: [String] = []
If tableview use NSManagedObject for create cell the simply add NSManagedObject data to the array.
for result in results as! [NSManagedObject] {
titlename.append(result)
}
OR
The tableview only use the string from titlename array for creating cell then just change the type NSManagedObject to String.
var titlename: [String] = []
This will help.
I'm developing an app to store one phone number at time using core data, the user should be able to enter a new phone number into ui text field,if it's equal to nil, it should store a new phone number,else it should replace old number with new number; it should store only one value.
but the code doesn't work as it should
what's wrong in my code?
let moContext: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = moContext.managedObjectContext
let phoneNu = NSEntityDescription.insertNewObjectForEntityForName("Setting", inManagedObjectContext: context)
let fetchRequest = NSFetchRequest(entityName: "Setting")
fetchRequest.predicate = NSPredicate(format: "phoneNumber = %#", phoneNumber)
// phoneNu.setValue(phoneNumber.text, forKey: "phoneNumber")
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneN = try context.executeFetchRequest(request)
if phoneN.count == 0{
phoneNu.setValue(phoneNumber.text, forKey: "phoneNumber")
}else if phoneN.count != 0{
for item in phoneN as! [NSManagedObject]{
let number = item.valueForKey("phoneNumber")
number?[0]?.setValue(phoneNumber.text, forKey: "phoneNumber")
}
}
}catch{
print("error")
}
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneNumber = try context.executeFetchRequest(request)
if phoneNumber.count > 0{
for item in phoneNumber as! [NSManagedObject]{
let number = item.valueForKey("phoneNumber")
print(number!)
}
}
}catch{
}
This is my solution
let moContext: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = moContext.managedObjectContext
guard let phoneNumber = phoneNumber.text where phoneNumber.characters.count > 0 else {
return// returns if textField is empty.
}
let fetchRequest = NSFetchRequest(entityName: "Setting")
fetchRequest.predicate = NSPredicate(format: "phoneNumber = %#", phoneNumber)
do{
let request = NSFetchRequest(entityName: "Setting")
let phoneObjectArray = try context.executeFetchRequest(request)
guard let settingFetched = phoneObjectArray as? [Setting] where settingFetched.count > 0 else {
// if enters here -> 0 phone numbers were found
if let setting = NSEntityDescription.insertNewObjectForEntityForName("Setting", inManagedObjectContext: context) as? Setting {
setting.phoneNumber = phoneNumber
// call context.save()
}
return // this I forgot
}
let settingObject = settingFetched.first
// fetch results return store phone number.
// update phone number
settingObject.phoneNumber = phoneNumber
// call context.save()
} catch let error as NSError! {
print("error: \(error)")
}
You need to call the "save()" function to persist the information.
I did some changes to the name variables, added some validations and assume some model class name based on your code.
I always recommend to use your NSManagedObject subclass (Setting I assume) instead of just using NSManagedObject and key/value coding.
There could be some minor syntax mistakes on the code because I was using a text editor.
Hope this helps!
For what you want to do, Core Data is overkill.
Use NSUserDefaults instead. So much easier.
I want to bind my 2 models with swift 2:
The "BodyPart" table :
The "Muscle" table :
I just want to save a "BodyPart" with its "Muscles":
if let managedObjectContext = self.managedObjectContext {
do{
// create a bodyPart
let bodyPart = NSEntityDescription.insertNewObjectForEntityForName("BodyPart",inManagedObjectContext: managedObjectContext) as! BodyPart
// create a Muscle
let muscle = NSEntityDescription.insertNewObjectForEntityForName("Muscle",inManagedObjectContext: managedObjectContext) as! Muscle
//muscles attributes
muscle.name = "test"
muscle.image = "myimage.png"
// mobdypart attributes
bodyPart.name="mybody-part test"
bodyPart.muscles = [muscle]
//save
try managedObjectContext.save()
// get all muscles
let fetchRequest = NSFetchRequest(entityName: "BodyPart")
/* Get result array from ManagedObjectContext */
let fetchResults = try managedObjectContext.executeFetchRequest(fetchRequest)
// list body parts
if let results: Array = fetchResults {
for obj:AnyObject in results {
let name:String? = obj.valueForKey("name") as? String
print("name for the BodyPart: \(name) ")
// list muscles => always empty !!
if let muscles: Array<Muscle> = obj.valueForKey("muscles") as? Array<Muscle> {
for ob:Muscle in muscles {
print("### name for the muscles: \(ob.name)")
}
}
}
} else {
print("Could not fetch")
}
} catch let error as NSError {
print(error)
}
}
BodyPart is saved in the CodeData, however the Muscles list is empty.
Thank you
The default collection type of Core Data is NSSet rather than NSArray
You can get allObjects from the set which returns an array
if let muscles: Array<Muscle> = (obj.valueForKey("muscles") as! NSSet).allObjects as? Array<Muscle> { ...
But since you know from the Core Data model that muscles exists, I'd recommend to declare the attribute as non-optional and omit the optional binding.
let muscles = obj.valueForKey("muscles") as! NSSet