2017-01-24 34 views
0

我試圖讓程序檢查導航標題,然後相應地填充單元格。硬編碼數組很容易,但使用核心數據對象會讓事情變得艱難。根據頁面標題動態填充單元格

初始化器 - 3個產品爲每個公司和空數組檢查網頁的標題後,將它們設置爲:

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中 - 檢查頁面標題和填充空數組,然後設置所需核心數據刪除持久性時:

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)") 
     } 

} 

最後的標籤設置在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 
} 

單元格應該在第一次嘗試時填充 - 即如果在前一個屏幕中點擊「Apple」,單元格會顯示Apple的3種產品。但是如果我回過頭來點擊「Google」,那麼這些單元現在會展示Apple的3款產品以及Google的3款產品,等等。

我該怎麼做才能使cell.textLabel?.text = product.value(forKey: "name") as? String只加載該公司的產品?

編輯:viewWillAppearsave方法:

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)") 
    } 
} 

最後編輯 - 在一個設定的所有默認值去

// 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

你有,也許通過執行讀取請求,例如更新'products'陣列,任何其他代碼。在'viewWillAppear'還是其他生命週期方法之一? – pbasdf

+0

@pbasdf是的,我編輯我的問題,包括'viewWillAppear'以及'save'方法。任何幫助將大力讚賞! – d0xi45

+0

謝謝 - 這解釋了你正在觀察。獲取請求(在viewWillAppear中)獲取所有內容;你需要一些方法來區分蘋果的產品和谷歌(和其他人)的產品。您可以通過向產品實體添加「公司」屬性或向「公司」實體添加關係來實現此目的。您還需要修改代碼以僅加載一次這些默認值。稍後我會添加完整的答案... – pbasdf

回答

1

首先創建一個關係從CompanyProduct,並將其命名爲「產品」。每個Company可以有很多Products,所以建立關係「對多」。同樣,從ProductCompany創建一個關係,並將其命名爲「company」。每個Product僅與一個Company(我假設)有關,因此建立關係「一對一」,並將其相反設置爲「產品」。

爲了讓生活更輕鬆,請在創建默認Company數據的同時添加默認值(不確定您現在正在做什麼)。請注意,我已經改變了你的產品5個陣列轉換成字典(defaultProducts),與該公司名稱的關鍵是:這使得它更容易地加載到CoreData一氣呵成:

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() 
    } 
} 

在您的視圖控制器,你可以刪除代碼以設置viewDidLoad的默認產品。

您正在用導航項目標題來確定應顯示哪個公司產品。因此,在viewWillAppear中,您需要修改提取以限制結果。使用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

你現在是我的英雄,非常感謝你這麼全面的回答!絕對有助於我理解如何更有效地使用Core Data。 – d0xi45

+0

快速更新 - 我正在嘗試將此解決方案應用到我設置默認公司的相同位置(應用程序與這5個默認公司一起啓動,每個產品有3個產品,然後讓用戶根據需要刪除和添加)。我喜歡用字典來分配每個公司的產品,但我不確定如何將它應用到我的功能中。如果你想看一看(或者我可以做一個單獨的問題),我會在我的問題的底部粘貼'setDefaults()'函數,但如果你沒有時間,不要爲此付出汗水,已經得到了巨大的幫助! – d0xi45

+0

@ d0xi45我已經編輯了我的答案 - 你非常接近:設置產品需要位於引號循環中的引號內,以便爲每個公司設置它們。 – pbasdf

0

你執行你的switch self.navigationItem.title! {之前,請重置您的數組是這樣的:

defaultProducts.removeAll() 

你的vi ewController可能不會被釋放,因此defaultProducts陣列保留了其以前的項目。通過在填充之前清除它,該問題應該消失。

+0

我剛剛嘗試過(在switch語句之前放入'viewDidLoad'),它不能工作。 – d0xi45

+0

你可以發佈你的numberOfRows:部分代碼嗎? – CodeBender

+0

我返回'products.count',產品是'var products = [NSManagedObject]()' – d0xi45