Unable to display table view on Swift 3 - ios

I’m currently trying to load out my tableview using these codes, however I get a thread breakpoint at return listitem.count. Any help to solve this problem would be great.
The following below are my codes:
import UIKit
import CoreData
class ViewInventoryTableController: UITableViewController{
var listItems = [NSManagedObject]()
override func viewDidLoad(){
super.viewDidLoad()
//Do any additional setup after loading the view, typically from a nib.
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(ViewInventoryTableController.addItem))
}
func addItem(){
let alertMessage = "Please key in the activation code"
let alertController = UIAlertController(title: "Add Item", message: alertMessage as String, preferredStyle: .alert)
//Add the textfield
var activationCodeTextField1: UITextField?
alertController.addTextField { (textField) -> Void in
activationCodeTextField1 = textField
activationCodeTextField1?.placeholder = "123456789"
}
// Create Cancel button
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in
print("Cancel button tapped")
}
alertController.addAction(cancelAction)
// Create ConfirmAction
let confirmAction = UIAlertAction(title: "Confirm", style: UIAlertActionStyle.default, handler: ({
(_) in
if let field = alertController.textFields![0] as? UITextField{
self.saveItem(itemToSave: field.text!)
self.tableView.reloadData()
}
}
))
alertController.addAction(confirmAction)
// Present Dialog message
OperationQueue.main.addOperation {
self.present(alertController, animated: true){}
}
print("Activation Code = \(activationCodeTextField1?.text)")
}
//function save item
func saveItem(itemToSave: String){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "ListEntity", in: managedContext)
let item = NSManagedObject(entity: entity!, insertInto: managedContext)
item.setValue(itemToSave, forKey: "item")
do {
try managedContext.save()
listItems.append(item)
}
catch {
print("error")
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.right)
managedContext.delete(listItems[indexPath.row])
listItems.remove(at: indexPath.row)
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//Dispose of any resources that can be recreated
}
override func tableView (_ tableView: UITableView , numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")! as UITableViewCell
let item = listItems[indexPath.row]
cell.textLabel?.text = item.value(forKey: "item") as? String
return cell
}
}

Related

How do I delete CoreData entries in a tableview that uses a persistentcontainer?

I am designing an app where users will key in information in an alert view with multiple textfields. These strings will then be combined and be saved in an attribute of an entity (as one entity). This will then be displayed in a tableview.
Now I would implement a way to delete entries should the user enter something wrong.
I have seen many places where they say use the following code to delete entries in CoreData:
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
let managedObjectContext = coreData.persistentContainer.viewContext
if editingStyle == .delete
{
movieToDelete = fetchedResultController.object(at: indexPath)
let confirmDeleteAlertController = UIAlertController(title: "Remove Movie", message: "Are you sure you would like to delete \"\(movieToDelete!.title!)\" from your movie library?", preferredStyle: UIAlertControllerStyle.actionSheet)
let deleteAction = UIAlertAction(title: "Delete", style: UIAlertActionStyle.default, handler: { [weak self] (action: UIAlertAction) -> Void in
managedObjectContext.delete((self?.movieToDelete!)!)
self?.coreData.saveContext()
self?.movieToDelete = nil
})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { [weak self] (action: UIAlertAction) -> Void in
self?.movieToDelete = nil
})
confirmDeleteAlertController.addAction(deleteAction)
confirmDeleteAlertController.addAction(cancelAction)
present(confirmDeleteAlertController, animated: true, completion: nil)
}
}
However, I was following a tutorial on youtube and as a result I do not have a ManagedObjectContext in my code to make use of the editingStyle.delete. Now I am stuck as to how to delete an entry. Do I change my earlier code to support a ManagedObjectContext or is there a way to delete the entries through persistent container?
This is the code in my viewController which I feel is important to the issue at hand:
class ViewController: UITableViewController {
var alarmItems: [NSManagedObject] = []
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
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: "AlarmItems")
do {
alarmItems = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}
#objc func addAlarmItem(_ sender: AnyObject) {
print("this works")
let alertController = UIAlertController(title: "Add New Item", message: "Please fill in the blanks", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
//combined string of attributes
let myStrings: [String] = alertController.textFields!.compactMap { $0.text }
let myText = myStrings.joined(separator: ", ")
self.save(myText)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
alertController.addTextField { (textField) in
textField.placeholder = "Enter Name of Engineer"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Date of Alarm in DD/MM/YYYY"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Time of Alarm in 24h (eg: 2300)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Please indicate True/False (type True or False)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Insert comments (if any), or NIL"
}
alertController.addAction(saveAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
func save(_ itemName: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "AlarmItems", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(itemName, forKey: "alarmAttributes")
do {
try managedContext.save()
alarmItems.append(item)
} catch let err as NSError {
print("Failed to save an item", err)
}
}
#objc func exportCSV(_ sender: AnyObject) {
//will work on exporting csv in the future
return
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return alarmItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let alarmItem = alarmItems[indexPath.row]
cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
return cell
}
/*
//create delete feature
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath ) {
if editingStyle == UITableViewCell.EditingStyle.delete {
}
}
*/
}
As you are using NSFetchedResultsController delete the data source array
var alarmItems: [NSManagedObject] = []
and all other occurrences of alarmItems. The NSFetchedResultsController instance becomes the data source array
In viewWillAppear just refetch the data
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
do {
try fetchedResultsController.performFetch()
tableView.reloadData()
} catch {
print(error)
}
}
Replace the datasource and delegate methods with
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sections?.count ?? 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let alarmItem = fetchedResultsController.object(at: indexPath) as! NSManagedObject
cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
return cell
}
Now your delete method is supposed to work.
Note:
You are encouraged to use always the NSManagedObject subclass AlarmItems ( by the way semantically each Core Data record represents one AlarmItem) and dot notation for example
let alarmItem = fetchedResultsController.object(at: indexPath) as! AlarmItem
cell.textLabel?.text = alarmItem.alarmAttributes

How to edit row in tableView and save changes in the coreData?

I created a simple toDoList with a simple coreData. Added creating a row, deleting a row, but can't change the row.
I can't understand how to do it.
I added alertСontroller to change it.
My coreData consists of one property: name.
And I make an interface without a storyboard, just code.
How to update a CoreData object?
import UIKit
import CoreData
class ViewController: UITableViewController {
private let cellID = "cell"
private var tasks = [Task]()
private let appDelegate = UIApplication.shared.delegate as! AppDelegate //
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "To do list"
navigationController?.navigationBar.barTintColor = UIColor(displayP3Red: 21/255,
green: 101/255,
blue: 192/255,
alpha: 1)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add",
style: .plain,
target: self,
action: #selector(addNewTask))
navigationController?.navigationBar.tintColor = .white
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
do {
tasks = try managedContext.fetch(fetchRequest)
} catch let error {
print("Failed to fetch data", error)
}
}
// MARK: Table View Data Source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let task = tasks[indexPath.row]
cell.textLabel?.text = task.name
return cell
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editNotesAction = UITableViewRowAction(style: .default, title: "Edit") { (action: UITableViewRowAction, indexPath: IndexPath) in
let alert = UIAlertController(title: "Edit", message: "", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action) in
})
let cancelAction = UIAlertAction(title: "Cancel", style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
self.present(alert, animated: true)
}
editNotesAction.backgroundColor = .blue
let deleteNotesAction = UITableViewRowAction(style: .default, title: "Delete") { (action: UITableViewRowAction, indexPath: IndexPath) in
let managedContext = self.appDelegate.persistentContainer.viewContext
managedContext.delete(self.tasks[indexPath.row])
self.tasks.remove(at: indexPath.row)
do {
try managedContext.save()
} catch let error {
print(error.localizedDescription)
}
self.tableView.deleteRows(at: [indexPath], with: .fade)
}
return [deleteNotesAction, editNotesAction]
}
#objc private func addNewTask() {
let alert = UIAlertController(title: "New Task", message: "", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { _ in
guard let task = alert.textFields?.first?.text, task.isEmpty == false else { return }
self.saveData(task)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
private func saveData(_ taskName: String) {
let managedContext = appDelegate.persistentContainer.viewContext
guard let entity = NSEntityDescription.entity(forEntityName: "Task", in: managedContext) else { return }
let task = NSManagedObject(entity: entity, insertInto: managedContext) as! Task
task.name = taskName
do {
try managedContext.save()
tasks.append(task)
} catch let error {
print("Failed to save task", error.localizedDescription)
}
}
}
Your save action needs to take the value out of the text field and assign it to the right managed object.
let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action) in
guard let textField = alert.textFields.first else { return }
let task = tasks[indexPath.row]
task.name = textField.text
})
If name is not optional you will need to use nil-coalescing to supply a default value for the name in case the text field is empty. (task.name = textField.text ?? "SomeDefaultName")

Swipe to delete with multiple options

When the user swipes a table view cell in the chat view controller I would like to offer the option to either Block and delete that user, or to only delete the chat from the user. Is there a way I can have the swipe to delete option to have both options available? Should I be adding the block user option on a different page or will there be a way to have both in the commit editingStyle function.
class Conversation {
var key:String
var sender:String
var recipient:String
var date:Date
var recentMessage:String
var seen:Bool
init(key:String, sender: String, recipient:String, date:Date, recentMessage:String, seen:Bool) {
self.key = key
self.sender = sender
self.recipient = recipient
self.date = date
self.recentMessage = recentMessage
self.seen = seen
}
// Returns the UID of the conversations partner
// i.e NOT the UID of the current user
var partner_uid:String {
guard let uid = Auth.auth().currentUser?.uid else { return "" }
if sender != uid {
return sender
}
return recipient
}
func printAll() {
print("key: \(key)")
print("sender: \(sender)")
print("recentMessage: \(recentMessage)")
}
}
class ChatsTableViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
var conversations = [Conversation]()
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds)
let nib = UINib(nibName: "ChatTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "chatCell")
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
title = "CHAT"
view.addSubview(tableView)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let cell = tableView.cellForRow(at: indexPath) as! ChatTableViewCell
let name = cell.usernameLabel.text!
let actionSheet = UIAlertController(title: "Block conversation with \(name)?", message: "Further messages from \(name) will be muted.", preferredStyle: .alert)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in }
actionSheet.addAction(cancelActionButton)
let deleteActionButton: UIAlertAction = UIAlertAction(title: "Block", style: .destructive)
{ action -> Void in
self.muteConversation(self.conversations[indexPath.row])
}
let deleteOnlyButton: UIAlertAction = UIAlertAction(title: "Only Delete", style: .destructive)
{ action -> Void in
print("only delete selected ")
}
actionSheet.addAction(deleteActionButton)
actionSheet.addAction(deleteOnlyButton)
self.present(actionSheet, animated: true, completion: nil)
}
}
func muteConversation(_ conversation:Conversation) {
guard let user = Auth.auth().currentUser else { return }
let ref = Database.database().reference()
let obj = [
"social/blocked/\(user.uid)/\(conversation.partner_uid)" : true,
"social/blockedBy/\(conversation.partner_uid)/\(user.uid)" : true,
"conversations/users/\(user.uid)/\(conversation.partner_uid)/muted": true
] as [String:Any]
print("OBBJ: \(obj)")
ref.updateChildValues(obj, withCompletionBlock: { error, ref in
if error != nil {
let alert = UIAlertController(title: "Error deleting conversation!", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
} else {
let alert = UIAlertController(title: "Conversation blocked!", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
}
})
}
}
Try this code and replace Action1 & Action2 with your preferred actions.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let action1 = UITableViewRowAction(style: .default, title: "Action1", handler: {
(action, indexPath) in
print("Action1")
})
action1.backgroundColor = UIColor.lightGray
let action2 = UITableViewRowAction(style: .default, title: "Action2", handler: {
(action, indexPath) in
print("Action2")
})
return [action1, action2]
}
Download/Refer https://github.com/CEWendel/SWTableViewCell/archive/master.zip, integrate this third party library to your project and try the below code in your ViewController
Step 1:
add the delegate SWTableViewCellDelegate to your ViewController
Step 2:
in your cellForRow
cell.leftUtilityButtons = leftButtons() as [AnyObject]
cell.rightUtilityButtons = self.rightButtons() as [AnyObject]
cell.delegate = self;
Step 3:
customise your left/right side buttons on swipes
func leftButtons() -> NSMutableArray
{
let leftUtilityButtons : NSMutableArray = NSMutableArray()
leftUtilityButtons.sw_addUtilityButton(with: UIColor.orange, title: "Block")
leftUtilityButtons.sw_addUtilityButton(with: UIColor.green, title: "Remove User")
return leftUtilityButtons
}
func rightButtons() -> NSMutableArray {
let leftUtilityButtons : NSMutableArray = NSMutableArray()
leftUtilityButtons.sw_addUtilityButton(with: UIColor.red, title: "Delete Chat")
return leftUtilityButtons
}
Step 4:
handle actions with these two delegate methods
// click event on left utility button
func swipeableTableViewCell(_ cell: SWTableViewCell, didTriggerLeftUtilityButtonWith index: Int)
{
switch index
{
case 0:
// Handle your button1 action (Block User)
break
case 1: break
// Handle your button2 action (Remove User)
default:
break
}
}
// click event on right utility button
func swipeableTableViewCell(_ cell: SWTableViewCell, didTriggerRightUtilityButtonWith index: Int)
{
//handle your right button action (Delete Chat)
}
Thats it...!
You can modify your function like this to work
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let blockAction = UITableViewRowAction(style: .normal, title: "Block") { (rowAction, indexPath) in
self.muteConversation(self.conversations[indexPath.row])
}
let deleteAction = UITableViewRowAction(style: .destructive, title: "Only Delete") { (rowAction, indexPath) in
print("only delete selected ")
}
blockAction.backgroundColor = UIColor.gray
return [blockAction, deleteAction]
}
and if you want to show action sheet instead you can use this code
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let moreAction = UITableViewRowAction(style: .normal, title: "More") { (rowAction, indexPath) in
self.showActionSheet(indexPath)
}
moreAction.backgroundColor = UIColor.blue
return [moreAction]
}
func showActionSheet(_ indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! ChatTableViewCell
let name = cell.usernameLabel.text!
let actionSheet = UIAlertController(title: "Block conversation with \(name)?", message: "Further messages from \(name) will be muted.", preferredStyle: .alert)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in }
actionSheet.addAction(cancelActionButton)
let deleteActionButton: UIAlertAction = UIAlertAction(title: "Block", style: .destructive)
{ action -> Void in
self.muteConversation(self.conversations[indexPath.row])
}
let deleteOnlyButton: UIAlertAction = UIAlertAction(title: "Only Delete", style: .destructive)
{ action -> Void in
print("only delete selected ")
}
actionSheet.addAction(deleteActionButton)
actionSheet.addAction(deleteOnlyButton)
self.present(actionSheet, animated: true, completion: nil)
}

Self.tableView.reloadData not working if there is no user tap or View change

I am having an issue; I have the following code that get execute in a IBAction and as you will see I have the code to execute reloadData of the tableView. The issue is if I don't touch the screen (like a tap or change of the view) no data is displayed in the tableView but as soon as I touch the screen or move the cells (like just move them up and down) then the data appears.
The following image is the code that imports the contacts, save them in core data and loads them into an Array and execute reload data.
Here is the complete code of the ViewController where this issue is happening.
import UIKit
import CoreData
import AddressBook
class ContactsViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableviewContacts: UITableView!
//Public property that represent an array of the contacts added or copied by the user using the application
var contacts: [Contact] = []
//Public property that represent the context required to save the data in the persistance storage.
var context: NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func viewWillAppear(animated: Bool) {
loadContacts()
tableviewContacts.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:cellContact = tableView.dequeueReusableCellWithIdentifier("cellContact", forIndexPath: indexPath) as! cellContact
let contact = contacts[indexPath.row]
cell.labelContact.text = contact.name + " " + contact.surname
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
var contact = contacts[indexPath.row]
var error: NSError?
var handler: HACoreDataHandler = HACoreDataHandler()
handler.context!.deleteObject(contact)
handler.context!.save(&error)
if(error != nil){
let alert = UIAlertController(title: "Error", message: error?.description, preferredStyle: UIAlertControllerStyle.Alert)
var dismiss = UIAlertAction(title: "Dismiss", style: .Default) { (alertAction: UIAlertAction!) ->
Void in
}
alert.addAction(dismiss)
presentViewController(alert, animated: true, completion: nil)
}
contacts.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
#IBAction func importContacts(sender: AnyObject) {
let status = ABAddressBookGetAuthorizationStatus()
if status == .Denied || status == .Restricted {
// user previously denied, to tell them to fix that in settings
let alert = UIAlertController(title: "Warning", message: "We need your permission to import your contacts to giftlog.", preferredStyle: UIAlertControllerStyle.Alert)
var dismiss = UIAlertAction(title: "Dismiss", style: .Default) { (alertAction: UIAlertAction!) ->
Void in
}
alert.addAction(dismiss)
self.presentViewController(alert, animated: true, completion: nil)
return
}
// open it
var error: Unmanaged<CFError>?
let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, &error)?.takeRetainedValue()
if addressBook == nil {
println(error?.takeRetainedValue())
return
}
ABAddressBookRequestAccessWithCompletion(addressBook) {
granted, error in
if !granted {
// warn the user that because they just denied permission, this functionality won't work
// also let them know that they have to fix this in settings
let alert = UIAlertController(title: "Warning", message: "Please grant access to your contact first by granting the acess to Giftlog in the privacy phone setting ", preferredStyle: UIAlertControllerStyle.Alert)
var dismiss = UIAlertAction(title: "Dismiss", style: .Default) { (alertAction: UIAlertAction!) ->
Void in
}
alert.addAction(dismiss)
self.presentViewController(alert, animated: true, completion: nil)
return
}
if let people = ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue() as? NSArray {
var handler: HACoreDataHandler = HACoreDataHandler()
var error: NSError?
for person:ABRecordRef in people{
if (ABRecordCopyValue(person, kABPersonFirstNameProperty) != nil){
var contact = NSEntityDescription.insertNewObjectForEntityForName("Contact", inManagedObjectContext: handler.context!) as! Contact
contact.name = (ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as? String)!
contact.surname = (ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue() as? String)!
var phones : ABMultiValueRef = ABRecordCopyValue(person,kABPersonPhoneProperty).takeUnretainedValue() as ABMultiValueRef
if (ABMultiValueGetCount(phones)>0){
let phoneUnmaganed = ABMultiValueCopyValueAtIndex(phones, 0)
contact.phone = phoneUnmaganed.takeUnretainedValue() as! String
}
let emails: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
if (ABMultiValueGetCount(emails)>0){
let index = 0 as CFIndex
let emailAddress = ABMultiValueCopyValueAtIndex(emails, index).takeRetainedValue() as! String
contact.email = emailAddress
}
handler.context!.save(&error)
if (error != nil){
let alert = UIAlertController(title: "Error", message: error?.description, preferredStyle: UIAlertControllerStyle.Alert)
var dismiss = UIAlertAction(title: "Dismiss", style: .Default) { (alertAction: UIAlertAction!) ->
Void in
}
alert.addAction(dismiss)
self.presentViewController(alert, animated: true, completion: nil)
} else {
self.contacts.append(contact)
self.tableviewContacts.reloadData()
} // else
} //if (ABRecordCopyValue(person, kABPersonFirstNameProperty) != nil)
} //for person:ABRecordRef in people
} // if let people
} // ABAddressBookRequestAccessWithCompletion
}
func loadContacts(){
var request = NSFetchRequest(entityName: "Contact")
let handler = HACoreDataHandler()
var error: NSError?
contacts = handler.context!.executeFetchRequest(request, error: &error) as! [Contact]
if(error != nil){
let alert = UIAlertController(title: "Error", message: error?.description, preferredStyle: UIAlertControllerStyle.Alert)
var dismiss = UIAlertAction(title: "Dismiss", style: .Default) { (alertAction: UIAlertAction!) ->
Void in
}
alert.addAction(dismiss)
presentViewController(alert, animated: true, completion: nil)
}
}
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
}
This image is the code that sets the label of each cell of the tableView.
Finally this is the image from the storyboard file of the view and the prototype cell
Any suggestions will be appreciated.
Thanks in advance.

App crashes because - "Class is not key value coding-compliant for the key"

My app crashes every time I go to VieController3 and I don't know why / how to solve the problem.
http://img3.fotos-hochladen.net/uploads/bildschirmfoto6cji4t9fp1.png
Terminating app due to uncaught exception 'NSUnknownKeyException', reason:'[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key tableView.'
import UIKit
import CoreData
class ViewController3: UIViewController, UITableViewDataSource {
var people = [NSManagedObject]()
#IBOutlet weak var tableView: UITableView!
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("Cell")
as UITableViewCell
let person = people[indexPath.row]
cell.textLabel!.text = person.valueForKey("name") as String?
return cell
}
#IBAction func addExercise(sender: AnyObject) {
var alert = UIAlertController(title: "New exercise",
message: "Add a new exercise",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default) { (action: UIAlertAction!) -> Void in
let textField = alert.textFields![0] as UITextField
self.saveName(textField.text)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
func saveName(name: String) {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let entity = NSEntityDescription.entityForName("Person",
inManagedObjectContext:
managedContext)
let person = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
//3
person.setValue(name, forKey: "name")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
//5
people.append(person)
}
override func viewDidLoad() {
super.viewDidLoad()
title = "\"Edit your Exercises\""
tableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//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 {
people = results
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The latest screenshot shows another error before that, which is probably causing the error below it.
Unknown class ViewController3 in InterfaceBuilder
To me that suggests you've tried to set a Class on a ViewController, but the class has been incorrectly entered. Did you create a class ViewController3 that inherits UIViewController?
Because of this the ViewController is defaulting to a default UIViewController, and UIViewController doesn't have a property tableView so it's crashing.
Hope that helps.

Resources