fetchedResultsController returns nil - ios

Trying to create simple application to display data from Core Data to Table View. The code builds successfully - every time it loads it adds new entry, currently more than 20 - but then it crashes when trying to build the table.
Here I have ViewController:
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var habitTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let habitClassName:String = String(describing: Habits.self)
let habit:Habits = NSEntityDescription.insertNewObject(forEntityName: habitClassName, into: DatabaseController.getContext()) as! Habits
habit.habitsPic = ":("
habit.positive = false
habit.theHabit = "do bad"
DatabaseController.saveContext()
let fetchRequest:NSFetchRequest<Habits> = Habits.fetchRequest()
do{
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
print("number of results: \(searchResults.count)")
}
catch{
print("Error \(error)")
}
}
//CONSTRUCT TABLE VIEW
func numberOfSectionsInTableView(tableView: UITableView)-> Int {
return fetchedResultsController.sections!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = fetchedResultsController.sections else {
fatalError("No sections in fetchedResultsController")
}
let sectionInfo = sections[section]
return sectionInfo.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "positiveCell", for: indexPath as IndexPath)
let habit = fetchedResultsController.object(at: indexPath as IndexPath) as! Habits
cell.textLabel?.text = habit.theHabit
cell.detailTextLabel?.text = habit.habitsPic
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//FOR DISPLAYING DATA IN TABLE
var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>!
func initializeFetchedResultsController() {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Habits")
let departmentSort = NSSortDescriptor(key: "theHabit", ascending: true)
let lastNameSort = NSSortDescriptor(key: "positive", ascending: true)
request.sortDescriptors = [departmentSort, lastNameSort]
let moc = DatabaseController.getContext()
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = (self as! NSFetchedResultsControllerDelegate)
do {
try fetchedResultsController.performFetch()
} catch {
fatalError("Failed to initialize FetchedResultsController: \(error)")
}
}
}
And DatabaseController:
import Foundation
import CoreData
class DatabaseController {
private init(){
}
class func getContext() -> NSManagedObjectContext{
return DatabaseController.persistentContainer.viewContext
}
let container = NSPersistentContainer(name: "ada")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
class func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
It will not build the table view, because the fetchedResultsController returns nil. I assume it is problem with "moc" variable, but what?
EDIT
error:
fatal error: unexpectedly found nil while unwrapping an Optional value
line:
guard let sections = fetchedResultsController.sections else {

You declare your fetched results controller as an implicitly unwrapped optional:
var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>!
Its initial value is nil.
You also have a method called initializeFetchedResultsController that assigns a value to this property, but you never call that method. In a comment you said that you're calling it in this code:
guard let sections = fetchedResultsController.sections else {
fatalError("No sections in fetchedResultsController")
}
But that code never mentions the initializeFetchedResultsController method, and so it never calls that method.
You have an optional variable but you never assign it a value. So it never gets a value. So it's nil. This isn't a Core Data question, it's basic Swift. Properties don't get values unless you give them values, and you are not doing that.

Related

Deal with Core Data objects between views with Navigation Controller

I try to send coreData to another view controller when selecting row from UITableViewthrough didSelectRowAt function.
Moving to another view controller through navigationController?.pushViewController in didSelectRowAt works, but I don't know how to send core data specifically.
This post
almost matches what I'm trying to do,
but I don't know how to pass data if I'm not using the storyboard and programmatically load views using navigationController.
Specifically, I want to access and modify the cordData sent from the first controller from the second controller.
This is my code so far.
First View Controller
First VC contains table view
var items = [Item]() // this is coreData variable
...
override func viewWillAppear(_ animated: Bool) {
items = DBManager.share.fetchItems()
homeTableView.reloadData()
}
extension FirstVC : UITableViewDelegate, UITableViewDataSource {
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "homeCell", for: indexPath) as? HomeTableCell else { return UITableViewCell() }
let newItem = items[indexPath.row]
cell.homeCellTitle.text = newItem.title
cell.homeCellPrice.text = newItem.price
cell.homeCellPost?.text = newItem.post
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = self.items[indexPath.row]
guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as? SecondVC else {return}
self.navigationController?.pushViewController(vc, animated: true)
}
}
Second View Controller
class SecondVC: UIViewController {
var selectedItem: Item?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func editButtonPressed(_ sender: Any) {
// I don't know this part.
}
}
DBManager
handling coreData
import UIKit
import CoreData
class DBManager{
static let share = DBManager()
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "RC_week3")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}) //completion Handler
return container
}()
// MARK: - Core Data Saving support
lazy var context = persistentContainer.viewContext
func saveContext () {
if context.hasChanges {
do{
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
func fetchItems() -> [Item]
{
var Items = [Item]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Item.description())
do{
Items = try context.fetch(fetchRequest) as! [Item]
}catch{
print("fetching error")
}
return Items
}
}
NSManagedObject instances are reference types, just hand the instance over after instantiating the controller
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = self.items[indexPath.row]
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC") as! SecondVC
vc.selectedItem = selectedItem // <-- here pass the data
self.navigationController?.pushViewController(vc, animated: true)
}
Side note: guarding the controller it not necessary as the storyboard cannot be modified at runtime. If the code crashes it reveals a design mistake.
And if you replace NSFetchRequest<NSFetchRequestResult> with NSFetchRequest<Item> you get rid of the type cast.
func fetchItems() -> [Item]
{
let fetchRequest = NSFetchRequest<Item>(entityName: Item.description())
do {
return try context.fetch(fetchRequest)
} catch {
print("fetching error", error)
return []
}
}

I have some problem about show last saved CoreData data in tableView

I save data from MovieDetailViewController in coreData. I try to access coreData data from another controller. When I save the data to coreData and switch to another controller where I output the result in tableView, it doesn't show me the newly saved names there. When I delete the background and reopen it then it shows me the last saved data.
I need something similar to the tableView method tableView.reloadData().
class MovieDetailViewController: UIViewController {
var coreDataMovieName: [NSManagedObject] = []
var movie: Movie!
var detailsImageView: UIImage!
var movieName = ""
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = movie.title
//Detalebshi Photos gamochena
if let posterPath = movie.posterPath {
TMDBClient.downloadPosterImage(path: posterPath) { (data, error) in
guard let data = data else {
return
}
let image = UIImage(data: data)
self.imageView.image = image
self.detailsImageView = image
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Favorite")
do {
coreDataMovieName = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
func save(name: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Favorite", in: managedContext)!
let person = NSManagedObject(entity: entity, insertInto: managedContext)
person.setValue(name, forKeyPath: "movieName")
do {
try managedContext.save()
coreDataMovieName.append(person)
print("saved \(person)")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
#IBAction func coreDataFavoritesBtnTapped(_ sender: Any) {
save(name: movieName)
}
}
A controller where I try to access Core Data:
class CoreDataFavoritesViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var movie: [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "The List"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Favorite")
do {
movie = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
}
// MARK: - UITableViewDataSource
extension CoreDataFavoritesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movie.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let person = movie[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = person.value(forKeyPath: "movieName") as? String
return cell
}
}
You are appending Data after context save
coreDataMovieName.append(person)
do it before
try managedContext.save()

How do I delete an object for CoreData in Swift 4

So I've written some code to read information from CoreData.
func getData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
// let newSitting = NSEntityDescription.insertNewObject(forEntityName: "Sittings", into: context)
//get data from CoreData
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Sittings")
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject] {
if let sittingDate = result.value(forKey: "date") as? Date {
//add data to array
sittingsDatesArr.append(sittingDate)
}
}
}
else {
print ("database is empty")
}
}
catch {
print ("error")
}
}
And write data to CoreData,
func writeData(sitDate: Date) {
// setup CoreData
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newSitting = NSEntityDescription.insertNewObject(forEntityName: "Sittings", into: context)
newSitting.setValue(sitDate, forKey: "date")
do {
try context.save()
print ("-----SAVED-----")
}
catch {
print ("XXXXX THERE WAS AN ERROR XXXXXXX")
}
}
and all that seem to work OK.
But I can't seem to work out how to delete an entry when the user slides to delete the row in the UITableView.
So far I have this,
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long
// remove item from array
sittingsDatesArr.remove(at: indexPath.row)
// remove item from core data
//refresh
refresh()
}
}
For reference, this is the refresh function,
#objc func refresh(){
getData()
print("refreshed")
viewTable.reloadData()
}
if you want to remove a single object from your coredata try this code
let request = NSFetchRequest(entityName: "Person")
request.predicate = NSPredicate(format:"markedCell = %#", "Test")
if let results = context.executeFetchRequest(request, error: nil) as? [NSManagedObject] {
// Delete _all_ objects:
for object in results {
context.deleteObject(object)
}
// Or delete first object:
if results.count > 0 {
context.deleteObject(results[0])
}
} else {
// ... fetch failed, report error
}
if you want to remove all object from your core data try this
func deleteData(data : String) {
// data is entity name
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: data)
if let result = try? moc.fetch(fetchRequest){
for object in result {
moc.delete(object as! NSManagedObject)
}
}
do{
try moc.save()
print("saved")
}catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
So I ended up having to do this:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long
let date = sittingsDatesArr[indexPath.row]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Sittings")
request.predicate = NSPredicate(format:"date = %#", date as CVarArg)
let result = try? context.fetch(request)
let resultData = result as! [NSManagedObject]
for object in resultData {
context.delete(object)
}
do {
try context.save()
print("TABLEVIEW-EDIT: saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
// add general error handle here
}
//refresh
refresh()
}
}
seems to work, although its a bit slow to refresh the UITableView, working on that now.
Did you try this? Swift 3 Core Data Delete Object
All you have to do is delete the object and save the changes.
PersistenceManager.swift
import CoreData
class PersistenceManager {
static var shared: PersistenceManager = PersistenceManager()
var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Name")
container.loadPersistentStores(completionHandler: { (_, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
var context: NSManagedObjectContext {
return self.persistentContainer.viewContext
}
func fetch<T: NSManagedObject>(request: NSFetchRequest<T>) -> [T] {
do {
let fetchResult = try self.context.fetch(request)
return fetchResult
} catch {
print(error.localizedDescription)
return []
}
}
#discardableResult
func delete(object: NSManagedObject) -> Bool {
self.context.delete(object)
do {
try self.context.save()
return true
} catch {
return false
}
}
}
Delete data (ViewController)
let request = NSFetchRequest<NSManagedObject>(entityName: "Name")
var dataArray: [NSManagedObject] = []
//CoreData - Fetch
recentCompany = PersistenceManager.shared.fetch(request: request)
//CoreData - Delete
guard let value = self?.dataArray[indexPath.row] else { return }
PersistenceManager.shared.delete(object: value)

Invisible trouble to view the Core Data in TableViewCells

Did from the example: https://drive.google.com/open?id=0B3d4jY23eLOoejdRWkE0SG1VMkk
Step 1. I implemented the Core Data "Database". I have now 17 record and want to view all of them through the Cells in TableView ...
I did as like it was in tutorial, but it doesn't work. I wasted a week, and can't find an error :( It loads perfectly, but data is not displayed in cells :( So...
import Foundation
import CoreData
#available(iOS 10.0, *)
class DatabaseController
{
private init() { }
class func getContext() -> NSManagedObjectContext
{
return persistentContainer.viewContext
}
// MARK: - Core Data stack
static var persistentContainer: NSPersistentContainer =
{
let container = NSPersistentContainer.init(name: "Database")
//let container = NSPersistentContainer(name: "Database")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError?
{
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
class func saveContext ()
{
let context = persistentContainer.viewContext
if context.hasChanges
{
do {
try context.save()
}
catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Mainly 3 files ... save/get/persistant container in "DatabaseController.swift"
Next "AppDelegate.Swift"...
func applicationWillTerminate(_ application: UIApplication)
{
DatabaseController.saveContext()
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL =
{
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1] as NSURL
}()
lazy var managedObjectModel: NSManagedObjectModel =
{
let modelURL = Bundle.main.url(forResource: "Database", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? =
{
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("Database.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
do
{
try coordinator!.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
}
catch {
coordinator = nil
let dict = NSMutableDictionary()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
let error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict as? [AnyHashable : Any])
NSLog("Unresolved error \(String(describing: error)), \(error.userInfo)")
print(error.localizedDescription)
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? =
{
let coordinator = self.persistentStoreCoordinator
if coordinator == nil
{
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
Main functions responsible for DataCore
And final file for TableView. Before i made it as DataCore , cells were displayed like this
if indexPath.row == 0 {
cell.postImageView.image = UIImage(named: "ENTP")
cell.postTitleLabel.text = "ENTP"
cell.authorLabel.text = "Oleksandr Zheliezniak"
cell.authorImageView.image = UIImage(named: "author"):
} else if indexPath.row == 1 {
cell.postImageView.image = UIImage(named: "INTJ")
cell.postTitleLabel.text = "INTJ"
cell.authorLabel.text = "Gabriel Theodoropoulos"
cell.authorImageView.image = UIImage(named: "appcoda-300")
} else if indexPath.row == 2 {
cell.postImageView.image = UIImage(named: "ENTP")
cell.postTitleLabel.text = "ENTJ"
cell.authorLabel.text = "Gabriel Theodoropoulos"
cell.authorImageView.image = UIImage(named: "appcoda-300")
} else {
cell.postImageView.image = UIImage(named: "СеКс")
cell.postTitleLabel.text = "и виски"
cell.authorLabel.text = "Кокс Карибский))"
cell.authorImageView.image = UIImage(named: "appcoda-300")
}
Final file as below:
//
// PersonTableViewController.swift
//
// Created by Oleksandr Z 2017(c).
//
import UIKit
import Foundation
import CoreData
#available(iOS 10.0, *)
class PersonTableViewController: UITableViewController, NSFetchedResultsControllerDelegate
{
#IBAction func addButtonPressed(_ sender: Any)
{
switchScreen()
}
#IBOutlet weak var menuButton:UIBarButtonItem!
let moc: NSManagedObjectContext? = (UIApplication.shared.delegate as? AppDelegate)?.managedObjectContext
var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>?
var valueToPass:String!
//override var prefersStatusBarHidden: Bool {return true}
override func viewDidLoad()
{
super.viewDidLoad()
// MARK: - CORE DATA fetching out to the TableView
fetchedResultsController?.delegate = self
fetchedResultsController = NSFetchedResultsController(fetchRequest: IdentitiesFetchRequest(), managedObjectContext: self.moc!, sectionNameKeyPath: nil, cacheName: nil)
do
{
try fetchedResultsController?.performFetch()
}
catch let error as NSError
{
fatalError("Failed to initialize FetchedResultsController: \(error)")
}
//Visualization
if self.revealViewController() != nil
{
self.revealViewController().rearViewRevealWidth = 250
self.revealViewController().frontViewShadowRadius = 10
self.revealViewController().frontViewShadowColor = UIColor.black
self.revealViewController().frontViewShadowOpacity = 1
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
self.clearsSelectionOnViewWillAppear = true
}
func IdentitiesFetchRequest() -> NSFetchRequest<NSFetchRequestResult>
{
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Identity")
let sortDescriptor = NSSortDescriptor(key: "lastModified", ascending: true)
fetchRequest.predicate = nil
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.fetchBatchSize = 20
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc!, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController?.delegate = self
do
{
try fetchedResultsController?.performFetch()
}
catch
{
fatalError("Failed to initialize FetchedResultsController: \(error)")
}
return fetchRequest
}
//MARK: NSFetchedResultsController Delegate Functions
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete { }
switch editingStyle
{
case .delete:
do
{
moc?.delete(fetchedResultsController?.object(at: indexPath) as! Identity)
try moc?.save()
}
catch
{
print(error)
}
case .insert:
break
case .none:
break
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
{
switch type
{
case NSFetchedResultsChangeType.insert:
tableView.insertRows(at: NSArray(object: newIndexPath!) as! [IndexPath], with: UITableViewRowAnimation.fade)
break
case NSFetchedResultsChangeType.delete:
tableView.deleteRows(at: NSArray(object: indexPath!) as! [IndexPath], with: UITableViewRowAnimation.fade)
break
case NSFetchedResultsChangeType.move:
tableView.deleteRows(at: NSArray(object: indexPath!) as! [IndexPath], with: UITableViewRowAnimation.fade)
tableView.insertRows(at: NSArray(object: newIndexPath!) as! [IndexPath], with: UITableViewRowAnimation.fade)
break
case NSFetchedResultsChangeType.update:
tableView.cellForRow(at: indexPath! as IndexPath)
break
//default:
// break
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
{
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
{
tableView.endUpdates()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// Return the number of sections.
return fetchedResultsController?.sections?.count ?? 0
}
//Detailed viewCell
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
print("You selected cell #\(indexPath.row)!")
/*
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
valueToPass = currentCell.textLabel?.text
performSegue(withIdentifier: "yourSegueIdentifer", sender: self)
*/
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if (segue.identifier == "ShowPerson")
{
//var viewController = segue.destination as! PersonDetailViewController
//viewController.passedValue = valueToPass
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as!PersonTableViewCell
if let cellContact = fetchedResultsController?.object(at: indexPath) as? Identity
{
cell.textLabel?.text = "\(String(describing: cellContact.pName)), \(String(describing: cellContact.lastModified))"
}
let identityClassName:String = String(describing: Identity.self)
//let typeClassName:String = String(describing: Type.self)
let identity:Identity = NSEntityDescription.insertNewObject(forEntityName: identityClassName, into: DatabaseController.getContext()) as! Identity
//let type:Type = NSEntityDescription.insertNewObject(forEntityName: typeClassName, into: DatabaseController.getContext()) as! Type
let fetchRequest:NSFetchRequest<Identity> = Identity.fetchRequest()
do
{
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
print("number of results: \(searchResults.count)")
for result in searchResults as [Identity]
{
print("\(result.pName!) is \(result.accuracy)% Robesper. Updeted \(result.lastModified!).")
cell.postImageView.image = UIImage(named: "ENTP")
cell.postTitleLabel.text = identity.pName
cell.authorLabel.text = identity.imType
cell.authorImageView.image = UIImage(named: "author")
}
}
catch { print("Error: \(error)") }
return cell
}
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to toIndexPath: IndexPath) {
}
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
func switchScreen()
{
let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let vc : UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "PersonDetail") as UIViewController
self.present(vc, animated: false, completion: nil)
}
}
Tried solution: Can't show the core data in tableview Swift but it didn't help. Tried all similar topics but can't solve the problem.
You seem to have two separate CoreData stacks: one set up by the DatabaseController class, which uses the viewContext from a NSPersistentContainer (introduced in iOS10), and another set up in the AppDelegate, which uses what looks like standard boilerplate from the older project templates. Your FRC uses the latter, whilst the rest of your code uses the former.
Although these seem to use the same model file, I suspect they are using different persistent stores. I think if you change this line:
fetchedResultsController = NSFetchedResultsController(fetchRequest: IdentitiesFetchRequest(), managedObjectContext: self.moc!, sectionNameKeyPath: nil, cacheName: nil)
to:
fetchedResultsController = NSFetchedResultsController(fetchRequest: IdentitiesFetchRequest(), managedObjectContext: DatabaseController.getContext(), sectionNameKeyPath: nil, cacheName: nil)
your FRC will be using the same context as the code that creates objects, so you should see some results. There are other problems with your code, so as Tom Harrington says in comments, you should learn how to use the debugger to iron them out.
var identities : [Identity] = []
override func viewDidLoad()
{
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
I tried a lot. There is no matter which solution to use (extensions,lazy,direct).
You should create two variables fore sure : ONE for all data array; SECOND for single data in array.
That is the way how it works basically:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as!PersonTableViewCell
let identity = identities[indexPath.row]
cell.postImageView.image = UIImage(named: <picture name>)
cell.postTitleLabel.text = identity.<Your attribute of entity>
cell.authorLabel.text = identity.<Your attribute of entity>
cell.authorImageView.image = UIImage(named: <picture name>)
return cell
}

Not all cells loading in tableview, getting a blank screen instead. Xcode/Swift

I am able add all core data and save it alright, and even print it all to the logs. However when I try to fetch the core data and load it on to the table view, only the first couple cells actually load and everything below the loaded cells is just a blank screen.
Here is my view controller:
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var loggedIn = false
var managedObjectContext: NSManagedObjectContext? = nil
var detailViewController: DetailViewController? = nil
#IBOutlet var tableViewLoginButton: UIBarButtonItem!
#IBAction func tableViewLoginButtonAction(sender: AnyObject) {
shouldPerformSegueWithIdentifier("loginSegue", sender: nil)
}
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
if let ident = identifier {
if ident == "loginSegue" {
if loggedIn == true {
PFUser.logOutInBackgroundWithBlock({ (error) -> Void in
self.checkForUser()
})
return false
}
}
}
return true
}
func checkForUser() {
let currentUser = PFUser.currentUser()
if (currentUser != nil) {
loggedIn = true
tableViewLoginButton.title = "Logout"
} else {
loggedIn = false
tableViewLoginButton.title = "Login"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Code for Login and Sign Up
checkForUser()
coreDataSetup()
}
func coreDataSetup() {
// Code for fetching json data, saving as core data and loading to table view
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context : NSManagedObjectContext = appDel.managedObjectContext
let url = NSURL(string: "https://www.kimonolabs.com/api/6tewont8?apikey=CPMj8n9tabsEUqUjKEPiHOmVir5gZjfq")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!) { (data, response, error) -> Void in
if error != nil {
print(error)
} else {
// print(NSString(data: data!, encoding: NSUTF8StringEncoding))
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if jsonResult.count > 0 {
if let results = jsonResult["results"] as? NSDictionary {
if let eventData = results["collection1"] as? NSArray {
let request = NSFetchRequest(entityName: "ForumEvents")
request.returnsObjectsAsFaults = false
do {
let results = try context.executeFetchRequest(request)
if results.count > 0 {
for result in results {
context.deleteObject(result as! NSManagedObject)
do { try context.save() } catch {}
}
}
} catch {}
for event in eventData {
if let eventTitle = event["EventTitle"] as? NSDictionary {
if let eventTitleText = eventTitle["text"] as? String {
if let eventDate = event["EventDate"] as? String {
if let eventTicketLink = event["EventTicketLink"] as? NSDictionary {
if let eventLink = eventTicketLink["href"] as? String {
let newEvent : NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("ForumEvents", inManagedObjectContext: context)
newEvent.setValue(eventTitleText, forKey: "eventTitle")
newEvent.setValue(eventDate, forKey: "eventDate")
newEvent.setValue(eventLink, forKey: "eventLink")
do { try context.save() } catch {}
}
}
}
}
}
}
}
}
}
self.tableView.reloadData()
} catch {}
}
}
task.resume()
}
override func viewWillAppear(animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
if segue.identifier == "loginSegue" {
checkForUser()
}
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = self.fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
// Tried: return self.fetchedResultsController.fetchedObjects!.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
cell.textLabel!.text = object.valueForKey("eventTitle")!.description
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return false
}
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("ForumEvents", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "eventTitle", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
do {
try _fetchedResultsController!.performFetch()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil
func controllerWillChangeContent(controller: NSFetchedResultsController) {
self.tableView.beginUpdates()
}
}
Here is a screenshot of how the loaded cells turned out:
I have tried everything and have no idea what to try next!
Thanks in advance for any help.
Make sure the CoreData is correct. Then try this:
Change
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = self.fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
into
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.fetchResultController.fetchedObjects!.count
}

Resources