2017-01-24 4 views
0

Ich versuche es so zu machen, dass das Programm den Navigationstitel überprüft und dann die Zellen entsprechend auffüllt. Dies wäre bei hartkodierten Arrays einfach, aber die Verwendung eines Core Data-Objekts macht die Sache schwierig.Zellen dynamisch befüllen, abhängig vom Seitentitel

Initializers - 3 Produkte für jedes Unternehmen und ein leeres Array sie nach der Überprüfung der Seitentitel zu setzen:

let defaultProductsApple = ["iPhone", "iPad", "Macbook"] 
let defaultProductsGoogle = ["Search", "Firebase", "Magic Leap"] 
let defaultProductsFacebook = ["Facebook", "Instagram", "WhatsApp"] 
let defaultProductsTesla = ["Model S", "Model X", "PowerWall"] 
let defaultProductsTwitter = ["Twitter", "Periscope", "Vine"] 
var defaultProducts = [String]() 

viewDidLoad - den Seitentitel überprüfen und das leere Array füllen, dann auf Kerndatensatz für Persistenz beim Löschen:

override func viewDidLoad() { 
    super.viewDidLoad() 

    tableView.register(Cell.self, forCellReuseIdentifier: cellId) 

    // Navbar stuff 
    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(handleBackButton)) 
    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(handleAdd)) 

     let entity = NSEntityDescription.entity(forEntityName: "Product", in: managedContext)! 

     switch self.navigationItem.title! { 
     case "Apple": 
      defaultProducts = defaultProductsApple 
     case "Google": 
      defaultProducts = defaultProductsGoogle 
     case "Twitter": 
      defaultProducts = defaultProductsTwitter 
     case "Tesla": 
      defaultProducts = defaultProductsTesla 
     case "Facebook": 
      defaultProducts = defaultProductsFacebook 
     default: 
      defaultProducts = defaultProductsApple 
     } 

     for productName in defaultProducts { 
      let product = NSManagedObject(entity: entity,insertInto: managedContext) 
      product.setValue(productName, forKey: "name") 
      products.append(product) 
     } 
     do { 
      try managedContext.save() 
      tableView.reloadData() 
     } catch let error as NSError { 
      print("Could not save. \(error), \(error.userInfo)") 
     } 

} 

und setzte schließlich die Etiketten in cellForRow:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! Cell 
    let product = products[indexPath.row] 

    cell.textLabel?.text = product.value(forKey: "name") as? String 

    return cell 
} 

Die Zellen füllen sich wie beim ersten Versuch - d. H., Wenn ich im vorherigen Bildschirm auf "Apple" tippe, zeigen die Zellen mir die 3 Produkte von Apple an. Aber wenn ich dann zurück gehe und auf "Google" tippe, zeigen die Zellen jetzt die 3 Produkte von Apple sowie die 3 Produkte von Google an und so weiter und so fort.

Wie kann ich es so machen, dass cell.textLabel?.text = product.value(forKey: "name") as? String NUR die Produkte dieses Unternehmens lädt?

EDIT: viewWillAppear und die save Methoden:

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 

    //1 
    guard let appDelegate = 
     UIApplication.shared.delegate as? AppDelegate else { 
      return 
    } 

    let managedContext = 
     appDelegate.persistentContainer.viewContext 

    //2 
    let fetchRequest = 
     NSFetchRequest<NSManagedObject>(entityName: "Product") 

    //3 
    do { 
     products = 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: "Product", 
            in: managedContext)! 

    let product = NSManagedObject(entity: entity, 
            insertInto: managedContext) 

    product.setValue(name, forKey: "name") 

    do { 
     try managedContext.save() 
     products.append(product) 
    } catch let error as NSError { 
     print("Could not save. \(error), \(error.userInfo)") 
    } 
} 

Finale Bearbeiten - Setzen Sie alle Standardeinstellungen in einem Rutsch

// Default 5 companies at launch - user can delete/add/edit 
func setDefaults() { 

    let userDefaults = UserDefaults.standard 
    let defaultValues = ["firstRun" : true] 
    userDefaults.register(defaults: defaultValues) 

    if userDefaults.bool(forKey: "firstRun") { 

     let defaultProducts = ["Apple" : ["iPhone", "iPad", "Macbook"], 
           "Google" : ["Search", "Firebase", "Magic Leap"], 
           "Facebook" : ["Facebook", "Instagram", "WhatsApp"], 
           "Tesla" : ["Model S", "Model X", "PowerWall"], 
           "Twitter" : ["Twitter", "Periscope", "Vine"]] 

     let companyEntity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)! 
     let productEntity = NSEntityDescription.entity(forEntityName: "Product", in: managedContext)! 


     // Setting the default company data (name, logo, and stockPrice) 
     let url = URL(string: "https://query.yahooapis.com/v1/public/yql?q=select%20symbol%2C%20Ask%2C%20YearHigh%2C%20YearLow%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22AAPL%22%2C%22GOOG%22%2C%22TWTR%22%2C%22TSLA%22%2C%20%22FB%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys")! 
     let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
      if error != nil { 
       print(error!) 
      } else if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { 
       let json = JSON(data: data!) 
       if let quotes = json["query"]["results"]["quote"].array { 
        for quote in quotes { 
         let symbol = quote["symbol"].stringValue 
         let name = NSLocalizedString(symbol, comment:"") 
         let ask = quote["Ask"].stringValue 
         let company = NSManagedObject(entity: companyEntity,insertInto: managedContext) 
         company.setValue(name, forKey: "name") 
         company.setValue(name, forKey: "logo") 
         company.setValue(ask, forKey: "stockPrice") 
         companies.append(company) 
         print(json) 
        } 

        // Setting the default products - should I be doing this here too? 
        let companyProducts = defaultProducts[companyName] 

        // iterate through all those products names... 
        for productName in companyProducts { 
         // create the corresponding Product: 
         let product = NSManagedObject(entity: productEntity,insertInto: managedContext) 
         // set its name attribute... 
         product.setValue(productName, forKey: "name") 
         // then set the relationship to the relevant Company... 
         product.setValue(company, forKey: "company") 
        } 

        DispatchQueue.main.async { 
         do { 
          try managedContext.save() 
          vc.tableView.reloadData() 
          userDefaults.set(false, forKey: "firstRun") 
         } catch let error as NSError { 
          print("Could not save. \(error), \(error.userInfo)") 
         } 
        } 
       } 
      } else { 
       print("The data couldn't be loaded") 
      } 
     } 
     task.resume() 
    } 
} 
+0

Haben Sie einen anderen Code haben, der die 'Produkte' Array aktualisiert, vielleicht durch eine Abrufanforderung ausführt, z. B. in 'ViewWillAppear' oder einer der anderen Lifecycle-Methoden? – pbasdf

+0

@pbasdf Ja, ich habe meine Frage so bearbeitet, dass sie sowohl 'viewWillAppear' als auch' save' enthält. Jede Hilfe wird sehr geschätzt! – d0xi45

+0

Danke - das erklärt, was Sie beobachten. Die Abrufanforderung (in viewWillAppear) ruft alles ab; Sie brauchen eine Möglichkeit, die Produkte von Apple von denen von Google (und allen anderen) zu unterscheiden. Sie können dies entweder tun, indem Sie der Entität Product ein Attribut 'Firma' hinzufügen oder indem Sie einer Entität 'Firma' eine Beziehung hinzufügen. Sie müssen auch Ihren Code ändern, um diese Standardwerte nur einmal zu laden. Ich werde später eine vollständige Antwort hinzufügen ... – pbasdf

Antwort

1

Beginnen Sie mit dem Erstellen einer Beziehung von Company zu Product, und nennen Sie es "Produkte". Jeder Company kann viele Products haben, also machen Sie die Beziehung "zu-viele". Erstellen Sie ebenfalls eine Beziehung von Product zu Company und nennen Sie sie "Firma". Jede Product bezieht sich nur auf eine Company (ich nehme an), so machen Sie die Beziehung "to-one", und stellen Sie die Umkehrung auf "Produkte".

Um das Leben einfacher zu machen, fügen Sie die Standardwerte hinzu, während Sie Ihre Standarddaten Company erstellen (nicht sicher, wo Sie das jetzt tun). Beachten Sie, dass ich Ihre fünf Reihen von Produkten in einem Wörterbuch geändert haben (defaultProducts), mit dem Firmennamen als Schlüssel: Das macht es einfacher, in einem Rutsch in Coredata zu laden:

func setDefaults() { 
    let userDefaults = UserDefaults.standard 
    let defaultValues = ["firstRun" : true] 
    userDefaults.register(defaults: defaultValues) 

    if userDefaults.bool(forKey: "firstRun") { 
     let defaultProducts = ["Apple" : ["iPhone", "iPad", "Macbook"], 
           "Google" : ["Search", "Firebase", "Magic Leap"], 
           "Facebook" : ["Facebook", "Instagram", "WhatsApp"], 
           "Tesla" : ["Model S", "Model X", "PowerWall"], 
           "Twitter" : ["Twitter", "Periscope", "Vine"]] 

     let companyEntity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)! 
     let productEntity = NSEntityDescription.entity(forEntityName: "Product", in: managedContext)! 

     // Setting the default company data (name, logo, and stockPrice) 
     let url = URL(string: "https://query.yahooapis.com/v1/public/yql?q=select%20symbol%2C%20Ask%2C%20YearHigh%2C%20YearLow%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22AAPL%22%2C%22GOOG%22%2C%22TWTR%22%2C%22TSLA%22%2C%20%22FB%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys")! 
     let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
      if error != nil { 
       print(error!) 
      } else if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { 
       let json = JSON(data: data!) 
       if let quotes = json["query"]["results"]["quote"].array { 
        for quote in quotes { 
         let symbol = quote["symbol"].stringValue 
         let name = NSLocalizedString(symbol, comment:"") 
         let ask = quote["Ask"].stringValue 
         let company = NSManagedObject(entity: companyEntity,insertInto: managedContext) 
         company.setValue(name, forKey: "name") 
         company.setValue(name, forKey: "logo") 
         company.setValue(ask, forKey: "stockPrice") 
         companies.append(company) 
         // Move the default products code here: 
         let companyProducts = defaultProducts[name] 
         // iterate through all those products names... 
         for productName in companyProducts { 
          // create the corresponding Product: 
          let product = NSManagedObject(entity: productEntity, insertInto:managedContext) 
          // set its name attribute... 
          product.setValue(productName, forKey: "name") 
          // then set the relationship to the relevant Company... 
          product.setValue(company, forKey: "company") 
         } 

         print(json) 
        } 

        DispatchQueue.main.async { 
         do { 
          try managedContext.save() 
          vc.tableView.reloadData() 
          userDefaults.set(false, forKey: "firstRun") 
         } catch let error as NSError { 
          print("Could not save. \(error), \(error.userInfo)") 
         } 
        } 
       } 
      } else { 
       print("The data couldn't be loaded") 
      } 
     } 
     task.resume() 
    } 
} 

In Ihrem View-Controller, Sie kann den Code entfernen, um die Standardprodukte von viewDidLoad festzulegen.

Sie verwenden derzeit den Titel des Navigationselements, um zu ermitteln, welche Produkte des Unternehmens angezeigt werden sollen. In viewWillAppear müssen Sie Ihren Abruf ändern, um die Ergebnisse zu begrenzen.Verwenden Sie ein predicate:

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    //1 
    guard let appDelegate = 
     UIApplication.shared.delegate as? AppDelegate else { 
      return 
    } 
    let managedContext = 
     appDelegate.persistentContainer.viewContext 
    //2 
    let companyToDisplay = self.navigationItem.title! 
    let fetchRequest = 
     NSFetchRequest<NSManagedObject>(entityName: "Product") 
    fetchRequest.predicate = NSPredicate(format:"company.name == %@",companyToDisplay)  
    //3 
    do { 
     products = try managedContext.fetch(fetchRequest) 
    } catch let error as NSError { 
     print("Could not fetch. \(error), \(error.userInfo)") 
    } 
} 
+0

Du bist jetzt mein Held, vielen Dank für solch eine gründliche Antwort! Definitiv hilft mir zu verstehen, wie man mit Core Data effizienter arbeitet! – d0xi45

+0

Kurzes Update - Ich versuche, diese Lösung an den gleichen Ort zu bringen, an dem ich die Standardfirmen eingestellt habe (die App startet mit diesen 5 Standardfirmen mit je 3 Produkten, dann kann der Benutzer löschen und hinzufügen, wie er es wünscht). Ich liebe die Idee, ein Wörterbuch zu verwenden, um die Produkte eines jeden Unternehmens zuzuordnen. Ich bin mir nicht sicher, wie ich es in meine Funktion integrieren soll. Ich habe die 'setDefaults()' -Funktion am Ende meiner Frage eingefügt, wenn Sie einen Blick darauf werfen möchten (oder ich kann eine separate Frage stellen), aber schwitzen Sie es nicht, wenn Sie keine Zeit haben, Sie ' Ich war schon eine große Hilfe! – d0xi45

+0

@ d0xi45 Ich habe meine Antwort bearbeitet - Sie waren sehr nah dran: Die Produkte müssen innerhalb der 'for quote in quotes {}' - Schleife sein, um sie für jede Firma zu setzen. – pbasdf

0

Bevor Sie Ihre switch self.navigationItem.title! { ausführen, setzen Sie Ihr Array wie folgt:

defaultProducts.removeAll() 

Ihr vi ewController wird wahrscheinlich nicht freigegeben, daher behält das Array seine vorherigen Elemente bei. Wenn Sie es löschen, bevor Sie es ausfüllen, sollte dieses Problem verschwinden.

+0

Ich habe es gerade versucht (in 'viewDidLoad' vor der switch-Anweisung) und es hat leider nicht funktioniert. – d0xi45

+0

Können Sie Ihren numberOfRows: section code posten? – CodeBender

+0

Ich gebe 'products.count' zurück, Produkte sind' var products = [NSManagedObject]() ' – d0xi45

Verwandte Themen