UITableViewController: NSInternalInconsistencyException - ios

After searching for solution I cant resolve this issue,
I have this code to list the data from core data:
import UIKit
import CoreData
class ViewControllerClass: UITableViewController, NSFetchedResultsControllerDelegate{
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
var intermedioLat:String = ""
var intermedioLong:String = ""
#IBOutlet weak var listagem: UITableView!
var velocidade = ["40","50","70","90","100","120"]
func textFieldSouldReturn (textField: UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
override func viewDidLoad() {
print(intermedioLat)
print(intermedioLong)
fetchedResultController = getFetchedResultController()
fetchedResultController.delegate = self
fetchedResultController.performFetch(nil)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
func taskFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Radar")
let sortDescriptor = NSSortDescriptor(key: "descricao", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = fetchedResultController.sections?.count
return numberOfSections!
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRowsInSection = fetchedResultController.sections?[section].numberOfObjects
return numberOfRowsInSection!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Celula", forIndexPath: indexPath) as! UITableViewCell
let task = fetchedResultController.objectAtIndexPath(indexPath) as! Radar
cell.textLabel?.text = task.descricao
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let managedObject:NSManagedObject = fetchedResultController.objectAtIndexPath(indexPath) as! NSManagedObject
managedObjectContext?.deleteObject(managedObject)
managedObjectContext?.save(nil)
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.reloadData()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "fromEventTableToAddEvent"{
var enviaInterLat : adicionarRadar = segue.destinationViewController as! adicionarRadar
enviaInterLat.latitude = intermedioLat
var enviaInterLong : adicionarRadar = segue.destinationViewController as! adicionarRadar
enviaInterLong.longitude = intermedioLong
}}
}
and I have a error like this:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '-[UITableViewController
loadView] loaded the "TuG-ju-H3E-view-l3X-mv-HmR" nib but didn't get a
UITableView.'
*** First throw call stack: libc++abi.dylib: terminating with uncaught exception of type NSException
I dont know what more to do because I try everything

You declare your class as a UITableViewController in this case the view outlet must be connected to the table view. However if you want a view that contains a UITableView then simple make the controller a UIViewController which conforms to the UITableViewDelegate and UITableViewDataSource protocols and this will go away.
Change it to
class ViewControllerClass: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate

Related

Transformable Swift 3 NSManagedObject type NSAttributedString not working

Subclass of NSManagedObject given below where I have set Managed object type to NSAttributedString.
import Foundation
import CoreData
extension NoteData {
#nonobjc public class func fetchRequest() -> NSFetchRequest<NoteData> {
return NSFetchRequest<NoteData>(entityName: "NoteData")
}
#NSManaged public var image: NSData?
#NSManaged public var note: NSAttributedString?
}
A is my table view controller class where I want to fetch data
import UIKit
import CoreData
class TableViewController: UITableViewController
{
var fetchRequest : NSFetchRequest<NSFetchRequestResult>?
var noteData = [NoteData]()
#IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
load()
table.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
load()
table.reloadData()
}
func load()
{
let fetchRequest : NSFetchRequest <NoteData> = NoteData.fetchRequest()
do
{
let Data = try
databaseController.getContext().fetch(fetchRequest)
self.table.reloadData()
noteData = Data
}
catch
{
print("Error . \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return noteData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell:UITableViewCell = UITableViewCell()
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")!
let NoteData = noteData[indexPath.row]
NoteData.note?.setValue("hello", forKey: "mykey")
print ("\( cell.textLabel?.attributedText = NoteData.note?.value(forKey: "mykey") as! NSAttributedString)")
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "showItem"{
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPath(for: cell)
let itemController : mainViewController = segue.destination as! mainViewController
itemController.noteData = noteData[(indexPath?.row)!]
}
if segue.identifier == "showItem"{
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPath(for: cell)
let itemController : mainViewController = segue.destination as! mainViewController
itemController.noteData = noteData[(indexPath?.row)!]
}
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let target = noteData[indexPath.row]
databaseController.persistentContainer.viewContext.delete(target)
databaseController.saveContext()
load()
table.reloadData()
}
}
But I am getting error after doing everything The error is here :

How to have cells save text data from UITextView individually?

I have been wondering how to have cells save text data from UITextView individually, using CoreData. Do I need to segue or do something like that? I have no idea... Hopeless with my code skills.
Update:
This is MyMainViewController
let ENTITY_NAME = "Tasks"
let ATTRIBUTE_NAME = "desc"
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController = getFetchedResultController()
fetchedResultController.delegate = self
fetchedResultController.performFetch(nil)
}
// MARK:- PrepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "edit" {
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPathForCell(cell)
let taskController: myViewController = segue.destinationViewController as! myViewController
let task: Tasks = fetchedResultController.objectAtIndexPath(indexPath!) as! Tasks
taskController.task = task
}
}
// MARK:- Retrieve Tasks
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
func taskFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: ENTITY_NAME)
let sortDescriptor = NSSortDescriptor(key: ATTRIBUTE_NAME, ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
// MARK: - TableView data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = fetchedResultController.sections?.count
return numberOfSections!
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRowsInSection = fetchedResultController.sections?[section].numberOfObjects
return numberOfRowsInSection!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: AnyObject = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let task = fetchedResultController.objectAtIndexPath(indexPath) as! Tasks
cell.textLabel?!.text = task.desc.capitalizedString
return cell as! UITableViewCell
}
And I have another ViewController where a UITextView is only set, but I do not know how to have each cell have each different text data. Where and what code do I have to write?

popToRootViewControllerAnimated is not updating UITableView

I'm working on small CoreData program with one UITableView with embedded Navigation controller and UIViewController, where to add the CoreData.
The problem is that I can't figure out how to reload the data in the table after press the save button.
I have tried to use popToRootViewControllerAnimated(true) in the #IBAction func buttonSavePressed(sender: UIBarButtonItem), but this just send me to the TableView without reloading the data.
#IBAction func buttonSavePressed(sender: UIBarButtonItem) {
self.navigationController?.popToRootViewControllerAnimated(true)
}
I have also tried self.navigationController?.showViewController(contractsView, sender: storyboard) but this create another view in the stack, not the original, if I can explained like this.
#IBAction func buttonSavePressed(sender: UIBarButtonItem) {
let contractsView = self.storyboard?.instantiateViewControllerWithIdentifier("ContractsTableViewControllerStoryboardID") as ContractsTableViewController
self.navigationController?.showViewController(contractsView, sender: storyboard)
}
I am new with the programming, which means that I can not aways ask the right questions. So I am posting the code, which is in working stage without comments - sorry
// ContractsTableViewController.swift
import UIKit
import CoreData
class ContractsTableViewController: UITableViewController {
//, UITableViewDelegate, UITableViewDataSource
var totalContracts = 0
#IBOutlet var tableContracts: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
var appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
var context = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Contract")
request.returnsObjectsAsFaults = false
totalContracts = context.countForFetchRequest(request, error: nil)
println(totalContracts)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return totalContracts
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default")
var appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
var context = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Contract")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
var thisContract = results[indexPath.row] as Contract
cell.detailTextLabel!.text = "From" + " " + thisContract.stratdate + " " + "to" + " " + thisContract.enddate
cell.textLabel!.text = thisContract.workingdays + " " + "days" + " " + "as" + " " + thisContract.position + " " + "on" + " " + thisContract.ship
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default")
var appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
var context = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Contract")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
context.deleteObject(results[indexPath.row] as NSManagedObject)
context.save(nil)
totalContracts = totalContracts - 1
tableContracts.reloadData()
}
}
When your tableView controller loads back viewDidAppear function will called. so you can reload tableView into that function like this:
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
You can navigate to RootView this way:
self.navigationController?.popToRootViewControllerAnimated(true)
This is working fine.
HERE is your working project.
First of all, take the IBOutlet of UITableView in ContractsViewController. Then put the reload the tableview using the below code:
self.myTableView.reloadData()

Retrieve Random String from Core Data in Swift

I've searched for this answer but have come up empty handed. For some reason I'm drawing a blank on how to retrieve a random entry from a Core Data String attribute. I have everything else working - create, update, delete... but can't seem to get a handle on getting a random entry from the stack.
Feeling confused on this. Here is my code from my table view controller that mostly manages the core data.
import UIKit
import CoreData
class TaskManagerViewController: UITableViewController, NSFetchedResultsControllerDelegate {
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController = getFetchedResultController()
fetchedResultController.delegate = self
fetchedResultController.performFetch(nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "edit" {
let cell = sender as UITableViewCell
let indexPath = tableView.indexPathForCell(cell)
let taskController:TaskDetailViewController = segue.destinationViewController as TaskDetailViewController
let task:Tasks = fetchedResultController.objectAtIndexPath(indexPath!) as Tasks
taskController.task = task
}
}
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: taskFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
func taskFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Tasks")
let sortDescriptor = NSSortDescriptor(key: "desc", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
return fetchRequest
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// #pragma mark - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = fetchedResultController.sections?.count
return numberOfSections!
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRowsInSection = fetchedResultController.sections?[section].numberOfObjects
return numberOfRowsInSection!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
let task = fetchedResultController.objectAtIndexPath(indexPath) as Tasks
cell.textLabel.text = task.desc
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let managedObject:NSManagedObject = fetchedResultController.objectAtIndexPath(indexPath) as NSManagedObject
managedObjectContext?.deleteObject(managedObject)
managedObjectContext?.save(nil)
}
func controllerDidChangeContent(controller: NSFetchedResultsController!) {
tableView.reloadData()
}
}
func randomTask() -> Tasks {
let count=UInt32(fetchedResultController.fetchedObjects!.count)
let index=Int(arc4random_uniform(count))
return fetchedResultsController.fetchedObjects[index] as Tasks
}
This is the code that ultimately delivered the results I was looking for:
(I'm new at stack overflow so not sure how to select correct answer here.)
func randomTask() -> Tasks {
let count = UInt32(fetchedResultController.fetchedObjects!.count)
let index = Int(arc4random_uniform(count))
var results = fetchedResultController.fetchedObjects![index] as Tasks
answerLabel.text = results.valueForKey("desc") as NSString
return results
}

ios, swift, core data + multiple tables

I'm very new to ios and swift. On a single view, how can I send two different fetch requests to two different table views? I have a class level fetchReq function that uses NSPredicate to take a parameter and give me the varied results that I want. The only place that knows which table is which is the tablView func, but it looks like the decision about which data to load gets made immediately on viewDidLoad. Could some kind soul help me restructure the core data code so that I get a different fetch request for each table?
import UIKit
import CoreData
class CustomTableViewCell : UITableViewCell {
#IBOutlet var l1: UILabel?
#IBOutlet var l2: UILabel?
func loadItem(#number: String, name: String) {
l1!.text = number
l2!.text = name
}
}
class ViewController: UIViewController, UITableViewDelegate, NSFetchedResultsControllerDelegate, UITableViewDataSource {
#IBOutlet var tableView1: UITableView!
//this is my second table - Ive connected it in the IB to this VC. both tables work, but are identical
#IBOutlet var tableView2: UITableView!
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
//the filtering happens inside this function. it gets called via didLoad, not cellsForRows
func playerFetchRequest(playerType: String) -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Players")
let sortDescriptor = NSSortDescriptor(key: "number", ascending: true)
let filter = NSPredicate(format: "%K = %#", "type", playerType)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.predicate = filter
return fetchRequest
}
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: playerFetchRequest(playerType), managedObjectContext:managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
//remember: to create a table with multiple sections just implement the numberOfSectionsInTableView(_:) method
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let numberOfRowsInSection = fetchedResultController.sections?[section].numberOfObjects
{return numberOfRowsInSection} else {return 0}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (tableView == tableView2) {
var playerType = "Forward"
var cell:CustomTableViewCell = self.tableView1.dequeueReusableCellWithIdentifier("customCell") as CustomTableViewCell
let player = fetchedResultController.objectAtIndexPath(indexPath) as DataModel
cell.l2?.text = player.lastName + ", " + player.firstName
cell.l1?.text = player.number
println(tableView)
return cell
}
else {
var playerType = "Defender"
var cell:CustomTableViewCell = self.tableView2.dequeueReusableCellWithIdentifier("customCell") as CustomTableViewCell
let player = fetchedResultController.objectAtIndexPath(indexPath) as DataModel
cell.l2?.text = player.lastName + ", " + player.firstName
cell.l1?.text = player.number
println(tableView)
return cell
}
}
func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
println("You selected cell #\(indexPath.row)!")
}
override func viewDidLoad() {
var nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
tableView1.registerNib(nib, forCellReuseIdentifier: "customCell")
tableView2.registerNib(nib, forCellReuseIdentifier: "customCell")
fetchedResultController = getFetchedResultController()
fetchedResultController.delegate = self
fetchedResultController.performFetch(nil)
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func controllerDidChangeContent(controller: NSFetchedResultsController!) {
tableView1.reloadData()
tableView2.reloadData()
}
}
You need 2 fetchedResultsControllers with the two different fetch requests for each table. If your tables delegates and datasources are both this view controller, you'll need to switch and provide the corresponding content... for example:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (tableView == tableView2)
{
return fetchedResultController2.sections?[section].numberOfObjects
}
else
{
return fetchedResultController.sections?[section].numberOfObjects
}
}
Another option would be to create 2 custom MYTableViewDataSource objects and set the datasource for each table view to that... It might make it more obvious when you've got unexpected behaviour and make the data easier to control.
Just establish two separate NSFetchedResultsController objects, one for each table:
var forwardFetchedResultController: NSFetchedResultsController
var defenderFetchedResultController: NSFetchedResultsController
then in viewDidLoad create them with different NSFetchRequests for each. And in your tableView functions, use the correct fetched results controller for the correct table.

Resources