如何编写 swift 代码来显示 Yelp 星图?

How to write swift code to display Yelp Star Images?

嘿,我正在尝试使用 Yelp 的评论 API,但在 structuring/writing 显示不同 Yelp 星级评分所需的代码时遇到了问题。我没有问题得到响应(它是成功的)。 Yelp 提供了所有不同星级(5、4.5、4 等星级)的图像资产。因为评级响应是 Double,所以我将其转换为 String 值。至于知道调用哪个,我创建了一个枚举 class 以便它知道要使用哪个图像名称。使用该名称,我可以使用它来查找我需要的图像资产。

现在我以这种方式构建代码,我的应用程序崩溃了。 Xcode 将构建它,但在打开应用程序时,它会崩溃。

枚举class:

import Foundation
import UIKit

enum Rating: String {

case five = "regular_5"
case fourAndAHalf = "regular_4_half"
case four = "regular_4"
case threeAndAHalf = "regular_3_half"
case three = "regular_3"
case twoAndAHalf =  "regular_2_half"
case two = "regular_2"
case oneAndAHalf = "regular_1_half"
case one = "regular_1"
case zero = "regular_0"

}

Yelp 客服 class:

import Foundation
import Alamofire
import SwiftyJSON

class YelpClientService {

    static func getReviews(url: String, completionHandler: @escaping ([Review]?)-> Void)
{
    let httpHeaders: HTTPHeaders = ["Authorization": "Bearer \(UserDefaults.standard.string(forKey: "token") ?? "")"]

    //removing diacritics from the URL
    if let requestUrl = URL(string: url.folding(options: .diacriticInsensitive, locale: .current))
    {
        Alamofire.request(requestUrl, encoding: URLEncoding.default, headers: httpHeaders).responseJSON { (returnedResponse) in
            let returnedJson = JSON(with: returnedResponse.data as Any)
            let reviewArray = returnedJson["reviews"].array
            print(reviewArray as Any)

            var reviews = [Review]()

            for review in reviewArray! {

                let userName = review["user"]["name"].stringValue

                let ratingDouble = review["rating"].doubleValue
                let rating = String(ratingDouble)

                let text = review["text"].stringValue

                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

                let timeCreated =  formatter.date(from: review["time_created"].stringValue)


                let url = review["url"].stringValue

                let review = Review(rating: Rating(rawValue: rating)!, userName: userName, text: text, timeCreated: timeCreated!, url: url)
                reviews.append(review)

            }

            completionHandler(reviews)

        }
    }
    else
    {
        print("invalid url")
        completionHandler(nil)
    }
}

}

显示星星的视图控制器中的函数:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "reviewCell", for: indexPath) as! ReviewCell

    let review = reviewList[indexPath.row]

    print(review.userName)

    cell.userName.text = review.userName
    cell.reviewText.text = review.text

    cell.yelpStars.image = UIImage(named: review.rating.rawValue)




    //cell.date.text = review.timeCreated



    return cell

}

构建时的错误是:致命错误:在展开可选值时意外发现 nil。

我不确定出了什么问题。我将评级实例化为评级类型是否正确?我应该保留字符串吗?

我知道这是很长的代码,但我希望有人能帮忙!谢谢!

我确定它会崩溃。你写的方式。 let ratingDouble = review["rating"].doubleValue 你期待双倍。它将是 0、4.5、3.0 等。这将转换为字符串“0”、“4.5”、“3.0” etc.Then 您尝试使用 Rating(rawValue : rating)Rating 枚举来初始化评级没有这些原始值如“0”、“4.5”等,因此将返回 nil。你用'!'强行打开它,毫无疑问它会崩溃。 你需要像这样格式化你的枚举

    enum Rating: String {

    case five = "5.0"
    case fourAndAHalf = "4.5"
    case four = "4.0"
    case threeAndAHalf = "3.5"
    case three = "3.0"
    case twoAndAHalf =  "2.5"
    case two = "2.0"
    case oneAndAHalf = "1.5"
    case one = "1.0"
    case zero = "0.0"

getImageName()-> String {
switch self {
case five:
    return "ImageNameForFive"
case fourAndHalf:
    return "ImageNameForFourAndHalf.
......

}
}

    }

并更改

let rating = String(ratingDouble)

let rating = String.init(format: "%.1f", ratingDouble)

当 Swift 无法执行操作时,通常会在目标为 nilemptynon-existent 或 [ 时抛出错误 fatal error: unexpectedly found nil while unwrapping an Optional value. =17=]。

如果值可能是 nilemptynon-existentundefined;它被称为可选值。为了在我们的代码中使用这些值,我们必须解包它们。如果该值为 nilemptynon-existentundefined,如果未安全解包,我们的应用很可能会崩溃。

要在 swift 中安全地展开对象,我们可以使用 if letguard statement。只有在对象不是 null.

时,代码才会运行

最好安全地展开 swift 中的所有对象以防止崩溃。示例如下:

安全展开

// initalize a string that may be nil (an optional)
var string: String? = nil

// create a random number between 0-2
let randomNum:UInt32 = arc4random_uniform(3)

// create a switch to set the string value based on our number
switch (randomNum) {

case 0: 
   string = "Some String"

default:
  break

}

// attempt to print out our string

// using a guard statement
guard let string = string else {
   // handle if string is null
   return
}

// print the string from the guard
print(string)

// using if let
if let string = string {
   print(string)
} else {
  // handle string is null
}

不安全展开

// 初始化一个可能为 nil 的字符串(可选) 变量字符串:字符串? =无

// create a random number between 0-2
let randomNum:UInt32 = arc4random_uniform(3)

// create a switch to set the string value based on our number
switch (randomNum) {

case 0: 
   string = "Some String"

default:
  break

}

// attempt to print our string by forcefully unwrapping it even if it is null causing a crash if it is null
print(string!)

因此您可以看到不同之处,在第二个应用程序中,应用程序会崩溃并出现与您遇到的相同的错误,因为在随机数不为 0 的情况下,它无法展开可选值。

无需使用 if letguard 即可安全地展开对象。这被称为 inline conditional,它基本上是一个 if/else 子句,但速度更快。

内联条件

// if the string is null, it will print the value beside the two `??`
print(string ?? "This is what is printed if the string is nil")

现在您已经掌握了所有这些知识,您可以继续查看您的代码,看看您是否正在强行解包任何值。提示是您使用 ! 来执行此操作。

此外,您制作的枚举采用 "half" 之类的字符串值,而不是双精度值,即使它是像“0.5”这样的字符串。所以它也可能崩溃

我挑选出的一些可能导致崩溃的例子是:

for review in reviewArray! review["rating"].doubleValue Rating(rawValue: rating)! timeCreated!