2017-03-08 1 views
0

J'ai besoin de remplir ma vue de table avec les données de mes données de base. Je peux afficher mes lignes mais, je ne peux pas remplir mon tableview! J'utilise swift 3 et Xcode 8. Ceci est mon code, dans ce contrôleur je dois afficher la liste.Remplir TableView à partir de CoreData avec NSFetchRequest - SWIFT3 Xcode 8

class iTableViewController: UITableViewController, NSFetchedResultsControllerDelegate{ 
@IBOutlet var iTableView: UITableView! 


override func viewDidLoad(){ 
    super.viewDidLoad() 

    iTableView.dataSource = self 
    iTableView.delegate = self 

    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    let managerContext = appDelegate.persistentContainer.viewContext 
    let interventsFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Intervento") 

    do{ 
     //results 
     let fetchedIntervents = try managerContext.fetch(interventsFetch) as! [Intervento] 

     for interv in fetchedIntervents{ 
      print(interv.stampRow()) 
     } 

     NSLog(String(fetchedIntervents.count)) 
    }catch{ 
     fatalError("Failed to fetch employees: \(error)") 
    } 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
} 

//number of sections 
override func numberOfSections(in tableView: UITableView) -> Int { 
    return 1 
} 

//numer of rows 
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return 1 
} 

//cell 
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell") 

    cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator 

    //print the example cell 
    cell.textLabel?.text = "title" 
    cell.detailTextLabel?.text = "subtitle" 
    return cell 
} 

//swipe and delete 
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ 
    if(editingStyle == UITableViewCellEditingStyle.delete){ 
     //TODO 
    } 
} 

// click cell 
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ 
    performSegue(withIdentifier: "segueDetail", sender: self) 
} 


override func viewDidAppear(_ animated: Bool){ 
    //iTableView.reloadData() 
} 

override func viewWillDisappear(_ animated: Bool) { 
    //iTableView.reloadData() 
    //fetchData() 
} 
} 

c'est ma classe

extension Intervento { 

@nonobjc public class func fetchRequest() -> NSFetchRequest<Intervento> { 
    return NSFetchRequest<Intervento>(entityName: "Intervento"); 
} 

@NSManaged public var cliente: Int32 
@NSManaged public var dataFine: String? 
@NSManaged public var dataInizio: String? 
@NSManaged public var descrizione: String? 
@NSManaged public var foto: String? 
@NSManaged public var id: Int32 
@NSManaged public var stato: String? 
@NSManaged public var tecnico: String? 

func stampRow()->String{ 
    let v1 = String(id) + " " + String(cliente) + " " 
    let v2 = dataInizio! + " " + dataFine! + " " 
    let v3 = stato! + " " + tecnico! + " " + descrizione! 
    return v1 + v2 + v3 
} 
} 

et c'est le mon code pour enregistrer les données (cela fonctionne)

@IBAction func addButton(_ sender: Any){ 
    //genero la data 
    let dateFormatter = DateFormatter() 
    dateFormatter.dateFormat = "dd-MM-yyyy HH:mm" 
    let strDate = dateFormatter.string(from: myDatePicker.date) 

    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    let managerContext = appDelegate.persistentContainer.viewContext 
    let newInt = NSEntityDescription.insertNewObject(forEntityName: "Intervento", into: managerContext) 

    newInt.setValue(1, forKey: "id") 
    newInt.setValue(strDate, forKey: "dataInizio") 
    newInt.setValue("", forKey: "dataFine") 
    newInt.setValue(2, forKey: "cliente") 
    newInt.setValue("Matt", forKey: "tecnico") 
    newInt.setValue(stato[1], forKey: "stato") 
    newInt.setValue("", forKey: "descrizione") 
    newInt.setValue("", forKey: "foto") 

    do{ 
     try managerContext.save() 
     print("saved") 
    }catch let error as NSError{ 
     //errore salvataggio 
     print("Could not fetch \(error), \(error.userInfo)") 
    } 
} 
+1

Votre code est source de confusion. Un 'UITableViewController' contient une instance' UITableView' pré-établie avec un délégué et une source de données connectés. Utilisez-vous 'NSFetchedResultsController'? Le code est assez différent pour récupérer les données * manuellement *. Où se trouve votre tableau de sources de données? Et les noms de classe sont censés commencer par une lettre majuscule. – vadian

+0

PS: Créer un nouveau projet maître-détail avec la case à cocher Données de base cochée. Vous obtiendrez presque tout le code dont vous avez besoin gratuitement. – vadian

+0

merci, j'ai ajouté ma classe et le code pour enregistrer dans la base de données. Peut-être que je dois utiliser NsFetchedResultController, mais comment? :( – Matt

Répondre

1

Tout d'abord, votre classe doit mettre en œuvre ces protocoles:

UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate 

Vous pouvez charger da ta d'un stockage persistant avec ce code:

//load data 

//persistant container 
let persistentContainer = NSPersistentContainer.init(name: "Model") 

// 
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = { 
    // Create Fetch Request 
    let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest() 

    // Configure Fetch Request 
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)] 

    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    let managerContext = appDelegate.persistentContainer.viewContext 

    // Create Fetched Results Controller 
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil) 

    // Configure Fetched Results Controller 
    fetchedResultsController.delegate = self 

    return fetchedResultsController 
}() 

//carica 
func load(){ 
    //persistant container 
    persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in 
     if let error = error { 
      print("Unable to Load Persistent Store") 
      print("\(error), \(error.localizedDescription)") 
     } else { 
      do { 
       try self.fetchedResultsController.performFetch() 
      } catch { 
       let fetchError = error as NSError 
       print("Unable to Perform Fetch Request") 
       print("\(fetchError), \(fetchError.localizedDescription)") 
      } 

     } 
    } 
} 

override func viewDidLoad(){ 
    super.viewDidLoad() 

    iTableView.delegate = self 
    iTableView.dataSource = self 

    // trigger load 
    load() 
} 

Vos données seront récupérées et montreront parce que vous avez délégué iTableViewController par cette ligne de code:

// Configure Fetched Results Controller 
fetchedResultsController.delegate = self 

Pour faire ce travail, votre ViewController doit être conforme au protocole NSFetchedResultsControllerDelegate, ici vous pouvez trouver une implémentation possibile:

extension iTableViewController: NSFetchedResultsControllerDelegate { 

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
    iTableView.beginUpdates() 
} 

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
    iTableView.endUpdates() 
} 

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 
    switch (type) { 
    case .insert: 
     if let indexPath = newIndexPath { 
      iTableView.insertRows(at: [indexPath], with: .fade) 
     } 
     break; 
    case .delete: 
     if let indexPath = indexPath { 
      iTableView.deleteRows(at: [indexPath], with: .fade) 
     } 
     break; 
    case .update: 
     if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) { 
      configureCell(cell, at: indexPath) 
     } 
     break; 
    case .move: 
     if let indexPath = indexPath { 
      iTableView.deleteRows(at: [indexPath], with: .fade) 
     } 

     if let newIndexPath = newIndexPath { 
      iTableView.insertRows(at: [newIndexPath], with: .fade) 
     } 
     break; 
    } 
} 
} 

en conclusion, c'est le pleine mise en œuvre de votre iTableViewController (j'ai inclus aussi le code nécessaire pour la suppression d'une ligne):

class iTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{ 
@IBOutlet var iTableView: UITableView! 

//load data 

//persistant container 
let persistentContainer = NSPersistentContainer.init(name: "Model") 

// 
lazy var fetchedResultsController: NSFetchedResultsController<Intervento> = { 
    // Create Fetch Request 
    let fetchRequest: NSFetchRequest<Intervento> = Intervento.fetchRequest() 

    // Configure Fetch Request 
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dataInizio", ascending: false)] 

    let appDelegate = UIApplication.shared.delegate as! AppDelegate 
    let managerContext = appDelegate.persistentContainer.viewContext 

    // Create Fetched Results Controller 
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managerContext, sectionNameKeyPath: nil, cacheName: nil) 

    // Configure Fetched Results Controller 
    fetchedResultsController.delegate = self 

    return fetchedResultsController 
}() 

//carica 
func load(){ 
    //persistant container 
    persistentContainer.loadPersistentStores { (persistentStoreDescription, error) in 
     if let error = error { 
      print("Unable to Load Persistent Store") 
      print("\(error), \(error.localizedDescription)") 
     } else { 
      do { 
       try self.fetchedResultsController.performFetch() 
      } catch { 
       let fetchError = error as NSError 
       print("Unable to Perform Fetch Request") 
       print("\(fetchError), \(fetchError.localizedDescription)") 
      } 

     } 
    } 
} 


override func viewDidLoad(){ 
    super.viewDidLoad() 

    iTableView.delegate = self 
    iTableView.dataSource = self 

    // trigger load 
    load() 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
} 

//numero di sezioni 
func numberOfSections(in tableView: UITableView) -> Int { 
    return 1 
} 

//numero di righe 
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    guard let quotes = fetchedResultsController.fetchedObjects else { return 0 } 
    return quotes.count 
} 

//gestisco la cella 
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    //genero la cella 
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell") 

    configureCell(cell, at:indexPath) 
    return cell 
} 

//swipe and delete 
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ 
    if(editingStyle == .delete){ 

     // Fetch Quote 
     let quote = fetchedResultsController.object(at: indexPath) 

     // Delete Quote 
     quote.managedObjectContext?.delete(quote) 
    } 
} 

// click cell 
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ 
    performSegue(withIdentifier: "segueDetail", sender: self) 
} 


func configureCell(_ cell: UITableViewCell, at indexPath: IndexPath) { 

    //get intervento 
    let intervento = fetchedResultsController.object(at: indexPath) 

    //fill the cell 
    cell.textLabel?.text = intervento.dataInizio 
    cell.detailTextLabel?.text = "SOME_THING" 
} 

//quando appare aggiorno la table view 
override func viewDidAppear(_ animated: Bool){ 
    self.iTableView.reloadData() 
} 
} 

extension iTableViewController: NSFetchedResultsControllerDelegate { 

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
    iTableView.beginUpdates() 
} 

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
    iTableView.endUpdates() 
} 

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 
    switch (type) { 
    case .insert: 
     if let indexPath = newIndexPath { 
      iTableView.insertRows(at: [indexPath], with: .fade) 
     } 
     break; 
    case .delete: 
     if let indexPath = indexPath { 
      iTableView.deleteRows(at: [indexPath], with: .fade) 
     } 
     break; 
    case .update: 
     if let indexPath = indexPath, let cell = iTableView.cellForRow(at: indexPath) { 
      configureCell(cell, at: indexPath) 
     } 
     break; 
    case .move: 
     if let indexPath = indexPath { 
      iTableView.deleteRows(at: [indexPath], with: .fade) 
     } 

     if let newIndexPath = newIndexPath { 
      iTableView.insertRows(at: [newIndexPath], with: .fade) 
     } 
     break; 
    } 
} 
} 

Ne pas oublier d'utiliser toujours le même contexte lorsque vous effectuez des opérations avec vos données (par exemple lorsque vous ajouter de nouvelles données).

let appDelegate = UIApplication.shared.delegate as! AppDelegate 
let managerContext = appDelegate.persistentContainer.viewContext 

Pour un exemple complet vous devriez regarder ici: https://github.com/bartjacobs/ExploringTheFetchedResultsControllerDelegateProtocol

+0

wooow merci !! vous comprenez mon problème !!! IL FONCTIONNE! – Matt