2
votes

In this table view (override func tableView), I show points of interests, some loaded by default, others by the user. I can retrieve the name of the managed object, but when try to show the position, it fails.

I can't show the latitude and longitude in the TableViewCell. If I use the name keyword the name appears. Maybe I should do some kind of conversion from numbers, but where?

I also got this warning:

CoreData: warning: Unable to load class named 'PRODUCT_MODULE_NAME.ArcheoPOI' for entity 'ArcheoPOI'. Class not found, using default NSManagedObject instead.

This is my NSManagedContext

enter image description here

import UIKit
import CoreData

import CoreLocation

class AppiaTVC: UITableViewController, UITableViewDataSource, UITableViewDelegate {


    var places : [NSManagedObject] = []

    let myLocationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK : good way to set the reuse id of the cell
        //        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell") //alternative to put it in the
        //MARK : good way to set the table title
        title = "\"All the POI\""


    }





    //MARK: - Added for fetching data from CoreData
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        //1
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        let managedContext = appDelegate.managedObjectContext!      //needed to handel mangedObject (saving and fetching entries)

        //2
        let fetchRequest = NSFetchRequest(entityName:"ArcheoPOI")

        //3
        var error: NSError?

        let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject]

        if let results = fetchedResults {
            places = results
        } else {
            println("Could not fetch \(error), \(error!.userInfo)")
        }
    }




    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete method implementation.
        // Return the number of rows in the section.
        return places.count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("appiaCellID", forIndexPath: indexPath) as! AppiaTVCell

        cell.backgroundColor = UIColor.blueColor()
        if indexPath.row % 2 == 0 {
            //            cell.backgroundColor = UIColor(red: 143 / 255, green: 204 / 255, blue: 255 / 255, alpha: 1)
            //            cell.sweetTextView.backgroundColor = UIColor(red: 63 / 255, green: 159 / 255, blue: 255 / 255, alpha: 1)

        } else {
            //            cell.backgroundColor = UIColor(red: 63 / 255, green: 159 / 255, blue: 255 / 255, alpha: 1)
            //            cell.sweetTextView.backgroundColor = UIColor(red: 143 / 255, green: 204 / 255, blue: 255 / 255, alpha: 1)
        }


        let singlePlace = places[indexPath.row]
        //KVC is the only way to access data in CoreData (can't use a property) butwe could also use a more natural object-style person.name
        //        cell.textLabel!.text = singlePlace.valueForKey("name") as? String
        cell.cellNameLabel.text = singlePlace.valueForKey("name") as? String
        cell.cellLatitudeLabel.text = singlePlace.valueForKey("latitude") as? String //if I use "name" it works
        cell.cellLongitudeLabel.text = singlePlace.valueForKey("longitude") as? String //if I use "name" it works

        return cell
    }




    @IBAction func addPlaceButtonPressed(sender: UIBarButtonItem) {

        var alert = UIAlertController(title: "New place", message: "Add a new place", 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.names.append(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)

    }




    //MARK: - save data to CoreData - this function is called by the addName button
    func saveName(name: String) {
        //1
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        let managedContext = appDelegate.managedObjectContext!

        //2
        let entity =  NSEntityDescription.entityForName("ArcheoPOI", inManagedObjectContext: managedContext)   //NSEntityDescription is required

        let place = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)


        myLocationManager.startUpdatingLocation()
        let lat = myLocationManager.location.coordinate.latitude
        let lon = myLocationManager.location.coordinate.longitude
        myLocationManager.stopUpdatingLocation()
        println("************************")
        println(lat)
        println(lon)
        println("************************")


        //3
        place.setValue(name, forKey: "name")
        place.setValue(lat, forKey: "latitude")
        place.setValue(lon, forKey: "longitude")

        //4
        var error: NSError?
        if !managedContext.save(&error) {

            println("Could not save \(error), \(error?.userInfo)")

        }
        //5
        places.append(place)
    }




    //MARK - delete NSManagedObject
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

        switch editingStyle {

        case UITableViewCellEditingStyle.Delete:
            // remove the deleted item from the model
            let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
            let managedContext:NSManagedObjectContext = appDelegate.managedObjectContext!


            managedContext.deleteObject(places[indexPath.row] as NSManagedObject)
            places.removeAtIndex(indexPath.row)

            managedContext.save(nil)

            //tableView.reloadData()
            // remove the deleted item from the `UITableView`
            self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

        default:
            return

        }
    }




    @IBAction func BackButtonPressed(sender: UIBarButtonItem) {

        dismissViewControllerAnimated(true , completion: nil)

    }


}
2

2 Answers

0
votes

Change your code to

let latitude = singlePlace.valueForKey("latitude")
let longitude = singlePlace.valueForKey("longitude")
cell.cellLatitudeLabel.text = "\(latitude)" //if I use "name" it works
cell.cellLongitudeLabel.text = "\(longitude)" //if I use "name" it works

I also strongly encourage you to create a class which will manage your entity. You can find good instructions on how to do it here. This tutorial is in objective-c but since then nothing has changed much ;)

You will then be able to call singlePlace.latitutde instead of using valueForKey,

0
votes

This is for the CoreData warning you mentioned:

When view an entity on your .xcdatamodeld file, open the Utilities tab and look at the Data Model inspector section. There is a drop down list for Module. As of some of the newer Xcode 7 betas, it will say Current Product Module by default. Delete that and leave it blank. This should clear up your problem.