打开选项的最安全的方法

时间:2018-01-23 18:15:20

标签: swift api optimization error-handling optional

我完成了我的应用程序编码,现在是时候添加安全功能以防止崩溃。我没有实现正确的nil处理,测试显示从API中获取数据时发生了一些崩溃。

我的结构有点复杂,我迷失了自己试图实现安全性的事情,所以我希望你们有新的见解和最终最安全的方式来处理nil。我把我的代码退了几步,供你查看。

代码完成,您可以在Playground

中试用

以下是struct

struct Ripple : Decodable {
        private enum CodingKeys : String, CodingKey { case raw = "RAW" }
        let raw : RippleRAW
    }

    struct RippleRAW : Decodable {
        private enum CodingKeys : String, CodingKey { case xrp = "XRP" }
        let xrp : RippleCURRENCIES
    }

    struct RippleCURRENCIES : Decodable {
        private enum CodingKeys : String, CodingKey {
            case usd = "USD"
            case rub = "RUB"
        }
        let usd : RippleUSD?
        let rub : RippleRUB?
    }

    struct RippleUSD : Decodable {
        let price : Double
        let percentChange24h : Double

        private enum CodingKeys : String, CodingKey {
            case price = "PRICE"
            case percentChange24h = "CHANGEPCT24HOUR"
        }
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            percentChange24h = try container.decode(Double.self, forKey: .percentChange24h)
            do {
                price = try container.decode(Double.self, forKey: .price)
            } catch DecodingError.typeMismatch(_, _) {
                let stringValue = try container.decode(String.self, forKey: .price)
                price = Double(stringValue)!
            }
        }
    }

    struct RippleRUB : Decodable {
        let price : Double
        let percentChange24h : Double

        private enum CodingKeys : String, CodingKey {
            case price = "PRICE"
            case percentChange24h = "CHANGEPCT24HOUR"
        }
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            percentChange24h = try container.decode(Double.self, forKey: .percentChange24h)
            do {
                price = try container.decode(Double.self, forKey: .price)
            } catch DecodingError.typeMismatch(_, _) {
                let stringValue = try container.decode(String.self, forKey: .price)
                price = Double(stringValue)!
            }
        }
    }

这里我从API获取和解码数据:

enum MyErrorXRP : Error {
        case FoundNil(String)
    }

class RippleInfo : NSObject {

        func fetchRippleInfo(forCurrency currency: String, _ completion: @escaping (Ripple?, Error?) -> Void) {
            let url = URL(string: "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=XRP&tsyms=\(currency)")!
            let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                guard let data = data else { return }
                do {
                    if let rippleData = try? JSONDecoder().decode(Ripple.self, from: data) {
                        completion(rippleData, nil)
                    } else {
                        throw MyErrorXRP.FoundNil("rippleData")
                    }
                } catch {
                    print(error)
                }
            }
            task.resume()
        }
    }

这些是调用函数,在应用程序中用于更新标签:

func rippleDataUpdate() {
        if MainViewController.currencyRUB == true {
            RippleInfo().fetchRippleInfo(forCurrency: "RUB", { (ripple, error) in
                if ripple != nil {
                    print("ok ripple rub")
                } else {
                    print("notworking")
                }
                self.updateRippleUI(with: ripple!)
            })
        }
    }

    func updateRippleUI(with rippleInfo: Ripple) {
            MainViewController.rippleDoublePrice = Double((rippleInfo.raw.xrp.rub?.price)!)
            MainViewController.xrpPercent = Double((rippleInfo.raw.xrp.rub?.percentChange24h)!)

    }

所有这些代码都包含在MainViewController中,以便在Playground中使用以下变量运行:

class MainViewController : UIViewController {

    static var rippleDoublePrice : Double = 0
    static var xrpPercent : Double = 0
    static var currencyRUB : Bool = true
}

我有一些关于该做什么的想法,但事实上我需要能够通过相同的结构获取不同的东西让我感到困惑。

您有什么看法?

1 个答案:

答案 0 :(得分:0)

您可以尝试这样的事情:

func rippleDataUpdate() {
            if MainViewController.currencyRUB == true {
                RippleInfo().fetchRippleInfo(forCurrency: "RUB", { (ripple, error) in

                guard ripple != nil else {
                    return
                }

                self.updateRippleUI(with: ripple!)


                })
            }
        }


     func updateRippleUI(with rippleInfo: Ripple) {
         if let price = rippleInfo.raw.xrp.rub?.price {
            MainViewController.rippleDoublePrice = Double(price)
         }

        if let percent = rippleInfo.raw.xrp.rub?.percentChange24h {
            MainViewController.xrpPercent = Double(percent)
        }
     }