【问题标题】:Swift 3: What's the safest way to unwrap optional values coming from an array?Swift 3:解开来自数组的可选值的最安全方法是什么?
【发布时间】:2016-12-02 19:13:59
【问题描述】:

首先,我初始化变量以保存股票数据

var applePrice: String?
var googlePrice: String?
var twitterPrice: String?
var teslaPrice: String?
var samsungPrice: String?
var stockPrices = [String]()

我从 YQL 获取当前股票价格,并将这些值放入一个数组中

func stockFetcher() {

    Alamofire.request(stockUrl).responseJSON { (responseData) -> Void in
        if((responseData.result.value) != nil) {
            let json = JSON(responseData.result.value!)
            if let applePrice = json["query"]["results"]["quote"][0]["Ask"].string {
                print(applePrice)
                self.applePrice = applePrice
                self.tableView.reloadData()
            }
            if let googlePrice = json["query"]["results"]["quote"][1]["Ask"].string {
                print(googlePrice)
                self.googlePrice = googlePrice
                self.tableView.reloadData()
            }
            if let twitterPrice = json["query"]["results"]["quote"][2]["Ask"].string {
                print(twitterPrice)
                self.twitterPrice = twitterPrice
                self.tableView.reloadData()
            }
            if let teslaPrice = json["query"]["results"]["quote"][3]["Ask"].string {
                print(teslaPrice)
                self.teslaPrice = teslaPrice
                self.tableView.reloadData()
            }
            if let samsungPrice = json["query"]["results"]["quote"][4]["Ask"].string {
                print(samsungPrice)
                self.samsungPrice = samsungPrice
                self.tableView.reloadData()
            }
            let stockPrices = ["\(self.applePrice)", "\(self.googlePrice)", "\(self.twitterPrice)", "\(self.teslaPrice)", "\(self.samsungPrice)"]
            self.stockPrices = stockPrices
            print(json)
        }
    }
}

在 cellForRowAt indexPath 函数中我打印到标签

    if self.stockPrices.count > indexPath.row + 1 {
        cell.detailTextLabel?.text = "Current Stock Price: \(self.stockPrices[indexPath.row])" ?? "Fetching stock prices..."
    } else {
        cell.detailTextLabel?.text = "No data found"
    }

我遇到了打印当前股票价格的问题:可选(“股票价格”),带有可选的单词。我认为这是因为我给它一个可选值数组,但我有点不得不这样做,因为我实际上不知道是否会有来自 YQL 的数据,5 支股票中的一支可能是nil 而其他人有数据。通过阅读其他类似的问题,我可以看到解决方案是用! 解开值,但是当它是一个包含可能是nil 的数据的数组时,我不太确定如何实现该解决方案,而不仅仅是一个 Int 什么的。

我怎样才能在这里安全地打开包装并去掉 Optional 这个词?

【问题讨论】:

  • 不要添加使用字符串插值将数据添加到您的数组中;只需直接添加字符串(即[self.applePrice, self.googlePrice,...] 但邓肯的做法是正确的

标签: ios swift swift3


【解决方案1】:

首先:

任何时候你多次重复相同的代码块并且只将一个值从 0 增加到某个最大值,这就是代码异味。您应该考虑另一种处理方式。

你应该使用一个数组来做这个处理。

一组索引枚举怎么样:

enum companyIndexes: Int {
  case apple
  case google
  case twitter
  case tesla
  //etc...
}

现在您可以循环运行数组并更干净地安装您的值:

var stockPrices = [String?]()
Alamofire.request(stockUrl).responseJSON { (responseData) -> Void in
    if((responseData.result.value) != nil) {
        let json = JSON(responseData.result.value!)
        let pricesArray = json["query"]["results"]["quote"]
        for aPriceEntry in pricesArray {
           let priceString = aPriceEntry["ask"].string
           stockPrices.append(priceString)
        }
   }
}

并从数组中获取价格:

let applePrice = stockPrices[companyIndexes.apple.rawValue]

这将导致一个可选的。

您可以使用 nil 合并运算符 (??) 将 nil 值替换为“无可用价格”之类的字符串。

let applePrice = stockPrices[companyIndexes.apple.rawValue] ?? "No price available"

或如另一个答案所示:

if let applePrice = stockPrices[companyIndexes.apple.rawValue] {
   //we got a valid price
} else
   //We don't have a price for that entry
}

【讨论】:

  • 谢谢,这是一个很好的答案。我还是个新手,从未使用过枚举,您介意扩展如何实现该部分,以及它将在代码中的位置吗?还有在哪里放置代码来获取价格 - 在我假设的 stockPrices 函数中,在 for 循环之后?
  • 这是 Swift 101 的东西。将枚举定义放在文件的顶部。如果您只需要访问单个类的价格数组,请将其放在该类的定义中。如果您需要访问多个类的价格,请将其放在类的定义之上。
  • 将我发布的代码放入您的 Alamofire.request() 函数的完成处理程序中,就像您的一样。这是一种更简洁的方法来解析一系列股票的价格,而不是一遍又一遍地重复相同的代码。
  • 我的帖子旨在作为一般指南,介绍更好的做事方式,而不是完成的解决方案。您需要根据自己的需要对其进行调整。
  • 我刚开始一般的编程,这是一个练习项目,所以我非常感谢我能得到的任何指导。我已经实现了现在应该的代码方式,但在 letPriceString = aPriceEntry 行上仍然出现错误“类型字符串/json 没有下标成员”
【解决方案2】:

我是在 Xcode 之外编写的(所以可能会有错别字),但是这种逻辑应该可以工作。

if self.stockPrices.count > indexPath.row + 1 {
    var txt = "Fetching stock prices..."
    if let price = self.stockPrices[indexPath.row] {
        txt = price
    }
    cell.detailTextLabel?.text = txt
} else {
    cell.detailTextLabel?.text = "No data found"
}

【讨论】:

    【解决方案3】:

    为了安全展开使用该代码:

    if let currentStockPrice = self.stockPrices[indexPath.row]
    {
        // currentStockPrice available there
    }
    // currentStockPrice unavailable
    

    如果您需要一个接一个地解包多个变量,可能会导致代码不可读。在这种情况下使用这种模式

    guard let currentStockPrice = self.stockPrices[indexPath.row]
    else
    {
        // currentStockPrice is unavailable there
        // must escape via return, continue, break etc.
    }
    // currentStockPrice is available
    

    【讨论】:

      猜你喜欢
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 2021-09-14
      • 2020-09-07
      • 2013-12-01
      • 2011-05-16
      • 2012-06-17
      相关资源
      最近更新 更多