嗨我试图使用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中的Funcfunc 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。
我不确定出了什么问题。将评级实例化为评级类型是否正确?我应该保留它吗?
我意识到这是长代码,但我希望有人可以提供帮助!谢谢!
答案 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.
,nil
,empty
或non-existent
时,Swift无法执行操作时会引发错误undefined
。
如果值可能为nil
,empty
,non-existent
或undefined
;它被称为可选值。为了在我们的代码中使用这些值,我们必须解开它们。如果值为nil
,empty
,non-existent
或undefined
,则我们的应用很可能会在未安全解包的情况下崩溃。
要快速安全地展开对象,我们可以使用if let
或guard 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 let
或guard
的情况下安全地展开对象。这被称为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!