I am getting the following error while trying to do NSFetchRequest in Swift 3
Generic parameter 'ResultType' could not be inferred
i checked lots of links and i have not been able to figure how to solve it.
this is what am doing
ViewController.swift
func loadData(){
let request = NSFetchRequest(entityName: "Grocery") //Error occurs here(Generic parameter 'ResultType' could not be inferred)
do{
let results = try manageObjectContext.execute(request)
groceries = results as! [NSManagedObject]
tableView.reloadData()
}catch{
fatalError("Error is retriving Gorcery items")
}
}
Try this:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Grocery")
It should work :)
Therefore your code should Look like:
func loadData(){
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Grocery")
do{
let results = try manageObjectContext.execute(request)
groceries = results as! [NSManagedObject]
tableView.reloadData()
}catch{
fatalError("Error is retriving Gorcery items")
}
}
Credits: Nitesh Patil https://medium.com/#imnitpa/swift-3-core-data-7b00b50f5782
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let appDelegate = UIApplication.shared.delegate as!AppDelegate
let context = appDelegate.persistentContainer.viewContext
//adding new user and saving in database...
let newUser = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
newUser.setValue("Batman", forKey: "username")
newUser.setValue("Robin", forKey: "password")
do {
try context.save()
print("saved")
} catch {
print("Error occured...")
}
// restoring data back from database
let request = NSFetchRequest < NSFetchRequestResult > (entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let results =
try context.fetch(request)
if results.count > 0 {
for result in results as![NSManagedObject] {
if let username = result.value(forKey: "username") as ? String {
print(username)
}
}
}
else {
print("No results")
}
} catch {
print("Couldn't fetch results")
}
}
}
you can use this too:
let request : NSFetchRequest<Grocery> = Grocery.fetchRequest()
and you get results of the type [Grocery] when you execute the request:
let results : [Grocery] = try manageObjectContext.execute(request)
or
let results = try manageObjectContext.execute(request)
Related
I tried to store some data using CoreData.
I created Entity Name Users and some attributes namely age, username, password.
Successfully loading, retrieving.
When I delete some object in that entity using context.delete(user), It will be deleted but show nil after I retrieving again.
Showing nil for deleted object
Note: I write the code for predicate which format is "Username!=nil".
Is this the right way? or how to overcome without nil in core data?
import UIKit
import CoreData
class CoreDataVC: UIViewController {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
var context:NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addAction(_ sender: Any){
if let newUser = openDatabse(){
saveData(UserDBObj:newUser)
}
_ = fetchData()
}
#IBAction func deleteAction(_ sender: Any){
if let newUser = openDatabse(){
deleteData(UserObj: newUser)
}
_ = fetchData()
}
// MARK: Methods to Open, Store and Fetch data
func openDatabse() -> NSManagedObject?{
context = appDelegate.persistentContainer.viewContext
guard let entity = NSEntityDescription.entity(forEntityName: "Users", in: context) else {
print("Invalid Entity")
return nil
}
let newUser = NSManagedObject(entity: entity, insertInto: context)
return newUser
}
func deleteData(UserObj: NSManagedObject){
let result = self.fetchData()
if let data = result.last{
context.delete(data)
}
do {
try context.save()
}
catch{
print("Error on saving context")
}
_ = fetchData()
}
func saveData(UserDBObj:NSManagedObject)
{
UserDBObj.setValue("RDC1", forKey: "username")
UserDBObj.setValue("12341", forKey: "password")
UserDBObj.setValue("22", forKey: "age")
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed")
}
_ = fetchData()
}
func fetchData() -> [Users]
{
var users : [Users] = []
print("Fetching Data..")
let request = Users.fetchRequest()
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
users = result
for data in result {//as! [NSManagedObject] {
print("Username: ",data.username ?? "nil",", Age : ",data.age ?? "nil")
}
} catch {
print("Fetching data Failed")
}
return users
}
}
Thanks in Advance.
I'm trying to update an already saved entry in Core data, objectContext isn't nil neither is the managedObject. The new values get set to the managedObject with said Id. No errors are thrown when calling managedContext.save() but no changes are reflected in the coreData
I have tried using setValue() no avail and I have searched far and wide on google and stack overflow for a similar problem and most of the time it says to say that the managedObject is nil.
var taskName:String!
var resultsController: NSFetchedResultsController<Tasks>!
// MARK: - Properties
// Manage objects and update tasks
//var resultsController: NSFetchedResultsController<Tasks>!
var managedContext: NSManagedObjectContext!
var tasksArray = [NSManagedObject]()
var fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Tasks")
func settextfields() {
let res = resultsController.fetchedObjects!
print(res)
for r in res {
if r.name == taskName {
txt_name.text = "\(r.name ?? "Task name" )"
txt_date.text = "\(r.date ?? "Task date")"
segmentedBtn.selectedSegmentIndex = Int(r.priority)
}
}
}
func loadTable() {
let request: NSFetchRequest<Tasks> = Tasks.fetchRequest()
// Sort by date
let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
request.sortDescriptors = [sortDescriptor]
resultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: coreData.managedContext, sectionNameKeyPath: nil, cacheName: nil)
// Fetch data
do {
try resultsController.performFetch()
print("Fetch successful")
} catch {
print("Error performing fetch: \(error)")
}
}
#IBAction func saveEdit(_ sender: Any) {
guard let name = txt_name.text, !name.isEmpty else {
return
}
guard let date = txt_date.text, !date.isEmpty else {
return
}
do {
loadTable()
let res = resultsController.fetchedObjects!
for r in res {
i += 1
if r.name == taskName {
print(r)
guard let name = txt_name.text, !name.isEmpty else {
return
}
guard let date = txt_date.text, !date.isEmpty else {
return
}
do {
r.name = name
r.date = date
r.priority = Int16(segmentedBtn.selectedSegmentIndex)
}
do {
try managedContext.save()
print(managedContext, r)
dismiss(animated: true)
print("Edit Successful!")
} catch {
print("Error saving task: \(error)")
}
}
}
}
I actually rewrote the save function using predicate like the person above suggested and it worked. Then I added a viewWillLoad to the mainViewController to reload the tableView once the entry is updated
#IBAction func saveEdit(_ sender: Any) {
guard let name = txt_name.text, !name.isEmpty else {
return
}
guard let date = txt_date.text, !date.isEmpty else {
return
}
do {
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Tasks")
fetchRequest.predicate = NSPredicate(format: "name = %#", taskName)
let test = try managedContext.fetch(fetchRequest)
let obj = test[0] as! NSManagedObject
obj.setValue(name, forKey: "name")
obj.setValue(date, forKey: "date")
obj.setValue(Int16(segmentedBtn.selectedSegmentIndex), forKey: "priority")
do {
try managedContext.save()
dismiss(animated: true)
print("Edit Successful!")
} catch {
print("Error saving task: \(error)")
}
} catch {
print(error)
}
}
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")
}
I am trying to insert new data to existed core data .But the new data is repeating . what is the problem with my code ?
func getContext(){
let container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
let delegate = UIApplication.shared.delegate as? AppDelegate
if let context = container?.viewContext{
let request = NSFetchRequest<Mydata>(entityName: "Mydata")
do {
let searchResults = try context.fetch(request)
let person1 = searchResults[0]
if person1.value(forKey: "iD") as! String != self.myiddddddd {
let person = NSEntityDescription.insertNewObject(forEntityName: "Mydata",
person.setValue(nameFunc, forKey: "name")
person.setValue(imageArray, forKeyPath: "profimg")
person.setValue(postImageArray, forKeyPath: "mid_img")
person.setValue(myUId, forKey: "iD")
do{
try (context.save())
DispatchQueue.main.async(execute: { () -> Void in
self.myTable.reloadData()
})
}
catch
{
print(error)
}
catch {
}
}
} catch {
print("Error with request: \(error)")
}
}
}
"myiddddddd" is the newdata(post id ) from the json .Please help
I'm trying to make an array from my Viewcontroller equal to, the objects my core data has saved. I'm using core data and created an entity named Pokemon which has 3 attributes name, id and generation. In the app delegate, I use the following function to get Pokemon from this API. This is what I do to parse the data and save the context:
typealias DownloadCompleted = () -> ()
var pokemonId: Int16 = 0
func fetchPokemon(url: String, completed: #escaping DownloadCompleted) {
let context = coreData.persistentContainer.viewContext
let url = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: url) { (data, repsonse, error) in
if error != nil {
print(error!)
}
do {
let jsonResult = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
let jsonArray = jsonResult.value(forKey: "results") as! [[String: Any]]
for pokemonData in jsonArray {
self.pokemonId += 1
if self.pokemonId > 721 {
self.coreData.saveContext()
return
}
guard let name = pokemonData["name"] as? String else {
return
}
let pokemon = Pokemon(context: context)
pokemon.name = name
pokemon.id = self.pokemonId
print("Name: \(pokemon.name) Id:\(self.pokemonId)")
if self.pokemonId <= 151 {
pokemon.generation = 1
} else if self.pokemonId <= 251 {
pokemon.generation = 2
} else if self.pokemonId <= 386 {
pokemon.generation = 3
} else if self.pokemonId <= 493 {
pokemon.generation = 4
} else if self.pokemonId <= 649 {
pokemon.generation = 5
} else if self.pokemonId <= 721 {
pokemon.generation = 6
}
}
guard let nextURL = jsonResult.value(forKey: "next") as? String else {
self.coreData.saveContext()
return
}
DispatchQueue.main.async {
self.fetchPokemon(url: nextURL, completed: {
self.coreData.saveContext()
})
completed()
}
} catch let err {
print(err.localizedDescription)
}
}
task.resume()
}
This is how I call it in the appDelegate. Really don't know what to do in the middle of the fetchPokemon or how to call it in another view controller. So I left it blank, not sure if this has something to do with the problem I'm having.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let context = self.coreData.persistentContainer.viewContext
let pokemonListVC = self.window?.rootViewController as! PokemonListVC
pokemonListVC.context = context
fetchPokemon(url: pokemonAPI) {
}
return true
}
Im using this SQL-Light read-only app from the app store. I check the data and all 721 pokemon are saving. Now, I don't know how I would be able to make the array in my view controller equal to all 721 Pokemon saved. I added this code into my viewController.
class PokemonListVC: UIViewController {
weak var context: NSManagedObjectContext! {
didSet {
return pokemon = Pokemon(context: context)
}
}
var pokemon: Pokemon? = nil
lazy var pokemons = [Pokemon]()
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func loadData() {
pokemons = pokemon!.loadPokemon(generation: 1, context: context)
}
}
I've created an extension of my Pokemon entity and added a function loadPokemon that filters the Pokemon by generation. Here is the code.
extension Pokemon {
func loadPokemon(generation: Int16 = 0, context: NSManagedObjectContext) -> [Pokemon] {
let request: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()
request.predicate = NSPredicate(format: "generation = %#", generation)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
do {
let pokemons = try context.fetch(request)
print("My Pokemon count: \(pokemons.count)")
return pokemons
} catch let err {
print(err.localizedDescription)
}
return []
}
}
When I call the loadData in my ViewController it crashes. The array count is 0 and so is the one in the hero extension. So I don't how to make my array equal the Pokemon saved from coreData.
Would really appreciate any help provided. :)
Here is my deleteRecords code, which is also in my appDelegate. This deletes all records when app launches. I call this method at the very beginning of didFinishLaunchingWithOption function before the fetchPokemons.
func deleteRecords() {
let context = coreData.persistentContainer.viewContext
let pokemonRequest: NSFetchRequest<Pokemon> = Pokemon.fetchRequest()
var deleteRequest: NSBatchDeleteRequest
var deleteResults: NSPersistentStoreResult
do {
deleteRequest = NSBatchDeleteRequest(fetchRequest: pokemonRequest as! NSFetchRequest<NSFetchRequestResult>)
deleteResults = try context.execute(deleteRequest)
} catch let err {
print(err.localizedDescription)
}
}
As you are saying that you have sure that all the pockemon records are stored correctly in your coredata you can simply fetch records from your codedata by providing fetch request. I have created demo for contact storing and I can get all the contact by this fetch request you can try this code in your ViewController where you want to fetch all the record.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject> (entityName: "Pokemon")
do {
arrPockemon = try managedContext.fetch(fetchRequest)
}catch let error as NSError {
showAlert(string: error.localizedDescription)
}
try to get all records first and if you get all then work for filtering extension and all. hope it will help you. you can learn from here https://code.tutsplus.com/tutorials/core-data-and-swift-core-data-stack--cms-25065
save flag on userDefault.
//check for first time when app is installed first time(first time flag is not present so)
let userDefault = UserDefaults.standard.dictionaryRepresentation()
if userDefault.keys.contains("isDataAvailable") {
//key is availebe so check it
if userDefault["isDataAvailable"] as! String == "1"{
//no need to call server for data
}else{
//fetch data from server
// once you get data from server make isDataAvailable flage as 1
UserDefaults.standard.setValue("1", forKey: "isDataAvailable")
UserDefaults.standard.synchronize()
}
}
else{
//flag is not avalable so call server for data
// once you get data from server make isDataAvailable flage as 1
UserDefaults.standard.setValue("1", forKey: "isDataAvailable")
UserDefaults.standard.synchronize()
}