如何编写swift代码来显示Yelp Star Images?

时间:2017-07-22 19:37:09

标签: ios enums swifty-json yelp

嗨我试图使用Yelp的Review API,但在构建/编写显示不同Yelp Star Ratings所需的代码时遇到了麻烦。我没有问题得到答复(它成功)。 Yelp提供了所有不同星级(5,4.5,4等星)的图像资产。因为评级响应是Double,我将其转换为String值。至于知道要调用哪个,我创建了一个枚举类,以便它知道要使用哪个图像名称。使用该名称,我可以使用它来查找我需要的图像资产。

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

枚举类:

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客户服务类:

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

}

显示Star:

的View Controller中的Func
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。

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

我意识到这是长代码,但我希望有人可以提供帮助!谢谢!

2 个答案:

答案 0 :(得分:0)

我相信它会崩溃。你写它的方式。 let ratingDouble = review["rating"]。doubleValue你期待加倍。它将是0,4.5,3.0等。它将转换为字符串“0”,“4.5”“3.0”等。然后,您尝试使用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)

答案 1 :(得分:0)

当目标为fatal error: unexpectedly found nil while unwrapping an Optional value.nilemptynon-existent时,Swift无法执行操作时会引发错误undefined

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

要快速安全地展开对象,我们可以使用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的字符串(可选)     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 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”而不是double值,即使它是一个类似'0.5“的字符串。所以它也可能崩溃

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

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