Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在后台快速更新UITableView_Ios_Multithreading_Uitableview_Swift_Asynchronous - Fatal编程技术网

Ios 在后台快速更新UITableView

Ios 在后台快速更新UITableView,ios,multithreading,uitableview,swift,asynchronous,Ios,Multithreading,Uitableview,Swift,Asynchronous,我正在尝试在后台更新我的UITableView。当我当前的代码运行时,我有两个主要错误 更详细地说。我用coreData来填充单元格。但我还有两个API需要连接 现在。我有两个功能: loadSuggestions()和updateSuggestions() loadSuggestionsfills获取正确的信息并显示良好 updatesSuggestions删除所有当前数据,获取新数据,将其保存到CoreData中,然后重新加载UITableView。(此函数作为我的loadSuggestio

我正在尝试在后台更新我的UITableView。当我当前的代码运行时,我有两个主要错误

更详细地说。我用coreData来填充单元格。但我还有两个API需要连接

现在。我有两个功能:

loadSuggestions()
updateSuggestions()

loadSuggestions
fills获取正确的信息并显示良好

updatesSuggestions
删除所有当前数据,获取新数据,将其保存到CoreData中,然后重新加载
UITableView
。(此函数作为我的
loadSuggestions()
函数中的最后一项在后台运行)

所以我的主要问题是。就是当我加载建议时。如果在更新完成之前尝试与UITableView交互,我会得到错误:
致命错误:数组索引超出范围
原因很简单。我在函数的开头删除CoreData。在此期间,它希望我的数组为0,但向下滚动显然会尝试在数组索引之外加载数据

但是,我不知道如何解决上述问题

我的第二个次要问题是/performance/?updateSuggestions()完成后运行。直到几秒钟之后,或者如果我与
UITableView
交互,它才实际使用更改的数据更新我的
UITableView
。当然,它应该在完成更新后立即更新

我不知道如何解决这两个问题中的任何一个。这就是我来这里的原因

以下是我的两个函数代码:

加载建议()

和更新建议:

func updateSuggestions() {
    println("Updating Suggestions")
    if Reachability.isConnectedToNetwork() == false {
        println("ERROR: -> No Internet Connection <-")
    } else {
        // Delete all the current objects in the dataset
        let fetchRequest = NSFetchRequest(entityName: formulaEntity)
        let a = managedContext.executeFetchRequest(fetchRequest, error: nil) as! [NSManagedObject]
        for mo in a {
            managedContext.deleteObject(mo)
        }
        // Removing them from the array
        stocks.removeAll(keepCapacity: false)
        // Saving the now empty context.
        managedContext.save(nil)

        // Set up a fetch request for the API data
        let entity =  NSEntityDescription.entityForName(formulaEntity, inManagedObjectContext:managedContext)
        var request = NSURLRequest(URL: formulaAPI!)
        var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
        var formula = JSON(data: data!)

        // Loop through the api data.
        for (index: String, actionable: JSON) in formula["actionable"] {

            // Save the data into temporary variables
            stockName = actionable["name"].stringValue
            ticker = actionable["ticker"].stringValue
            action = actionable["action"].stringValue
            suggestedPrice = actionable["suggested_price"].floatValue
            weight = actionable["percentage_weight"].floatValue

            // Set up CoreData for inserting a new object.
            let stock = NSManagedObject(entity: entity!,insertIntoManagedObjectContext:managedContext)

            // Save the temporary variables into coreData
            stock.setValue(stockName, forKey: "name")
            stock.setValue(ticker, forKey: "ticker")
            stock.setValue(action, forKey: "action")
            stock.setValue(suggestedPrice, forKey: "suggestedPrice")
            stock.setValue(weight, forKey: "weight")

            // Get ready for second API call.
            var quoteAPI = NSURL(string: "http://dev.markitondemand.com/Api/v2/Quote/json?symbol=\(ticker)")

            // Second API fetch.
            var quoteRequest = NSURLRequest(URL: quoteAPI!)
            var quoteData = NSURLConnection.sendSynchronousRequest(quoteRequest, returningResponse: nil, error: nil)
            if quoteData != nil {
                // Save the data from second API call to temporary variables
                var quote = JSON(data: quoteData!)
                betterStockName = quote["Name"].stringValue
                lastPrice = quote["LastPrice"].floatValue

                println("Updated lastPrice for \(betterStockName)")

                // The second API call doesn't always find something, so checking if it exists is important.
                if betterStockName != "" {
                    stock.setValue(betterStockName, forKey: "name")
                }

                // This can simply be set, because it will be 0 if not found.
                stock.setValue(lastPrice, forKey: "lastPrice")

            } else {
                println("ERROR ----------------- NO DATA for \(ticker) --------------")
            }

            // Error handling
            var error: NSError?
            if !managedContext.save(&error) {
                println("Could not save \(error), \(error?.userInfo)")
            }
            // Append the object to the array. Which fills the UITableView
            stocks.append(stock)
        }

        self.tableView.reloadData()
        println("Finished Updating Suggestions")
    }
}
func更新建议(){
println(“更新建议”)
如果可达性.isconnectedtonework()=false{

普林顿("错误:->没有Internet连接我认为第二个问题是从后台线程调用reloadData造成的。对于第一个问题,您没有使用NSFetchedResultsController吗?保留数据,直到完成数据更新。然后用新数据替换旧数据。@rdelmar您是对的。将其移动到主线程修复了loading时间!再次感谢你。@Volker我理解这背后的逻辑。我不知道的是怎么做。因为我在循环每个API调用。我在保存数据。如何获取所有数据,保存它。然后只删除旧数据?
func updateSuggestions() {
    println("Updating Suggestions")
    if Reachability.isConnectedToNetwork() == false {
        println("ERROR: -> No Internet Connection <-")
    } else {
        // Delete all the current objects in the dataset
        let fetchRequest = NSFetchRequest(entityName: formulaEntity)
        let a = managedContext.executeFetchRequest(fetchRequest, error: nil) as! [NSManagedObject]
        for mo in a {
            managedContext.deleteObject(mo)
        }
        // Removing them from the array
        stocks.removeAll(keepCapacity: false)
        // Saving the now empty context.
        managedContext.save(nil)

        // Set up a fetch request for the API data
        let entity =  NSEntityDescription.entityForName(formulaEntity, inManagedObjectContext:managedContext)
        var request = NSURLRequest(URL: formulaAPI!)
        var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
        var formula = JSON(data: data!)

        // Loop through the api data.
        for (index: String, actionable: JSON) in formula["actionable"] {

            // Save the data into temporary variables
            stockName = actionable["name"].stringValue
            ticker = actionable["ticker"].stringValue
            action = actionable["action"].stringValue
            suggestedPrice = actionable["suggested_price"].floatValue
            weight = actionable["percentage_weight"].floatValue

            // Set up CoreData for inserting a new object.
            let stock = NSManagedObject(entity: entity!,insertIntoManagedObjectContext:managedContext)

            // Save the temporary variables into coreData
            stock.setValue(stockName, forKey: "name")
            stock.setValue(ticker, forKey: "ticker")
            stock.setValue(action, forKey: "action")
            stock.setValue(suggestedPrice, forKey: "suggestedPrice")
            stock.setValue(weight, forKey: "weight")

            // Get ready for second API call.
            var quoteAPI = NSURL(string: "http://dev.markitondemand.com/Api/v2/Quote/json?symbol=\(ticker)")

            // Second API fetch.
            var quoteRequest = NSURLRequest(URL: quoteAPI!)
            var quoteData = NSURLConnection.sendSynchronousRequest(quoteRequest, returningResponse: nil, error: nil)
            if quoteData != nil {
                // Save the data from second API call to temporary variables
                var quote = JSON(data: quoteData!)
                betterStockName = quote["Name"].stringValue
                lastPrice = quote["LastPrice"].floatValue

                println("Updated lastPrice for \(betterStockName)")

                // The second API call doesn't always find something, so checking if it exists is important.
                if betterStockName != "" {
                    stock.setValue(betterStockName, forKey: "name")
                }

                // This can simply be set, because it will be 0 if not found.
                stock.setValue(lastPrice, forKey: "lastPrice")

            } else {
                println("ERROR ----------------- NO DATA for \(ticker) --------------")
            }

            // Error handling
            var error: NSError?
            if !managedContext.save(&error) {
                println("Could not save \(error), \(error?.userInfo)")
            }
            // Append the object to the array. Which fills the UITableView
            stocks.append(stock)
        }

        self.tableView.reloadData()
        println("Finished Updating Suggestions")
    }
}