-2

I can't get alamofire to work on Xcode. I'm trying to json parse yahoo API and it won't work . for start i jut wanted to parse and print one element in of "struct Stock: Codable " which is "symbol"

any help would be appreciated

import UIKit
import SwiftUI
import UserNotifications
import Alamofire

struct QuoteParent: Codable {
    var quoteResponse: QuoteResponse
    init() {
        quoteResponse = QuoteResponse()
    }
}

struct QuoteResponse: Codable {
    var error: QuoteError?
    var result: [Stock]?
    init() {
        error = nil
        result = []
    }
}

struct QuoteError: Codable {
    var lang: String?
    var description: String?
    var message: String?
    var code: Int?
    init() {
        lang = ""
        description = ""
        message = ""
        code = 0
    }
}

struct Stock: Codable {
    var language : String?
    var region : String?
    var quoteType : String?
    var typeDisp : String?
    var quoteSourceName : String?
    var triggerable : String?
    var customPriceAlertConfidence : String?
    var exchange : String?
    var exchangeTimezoneName : String?
    var exchangeTimezoneShortName : String?
    var gmtOffSetMilliseconds : String?
    var market : String?
    var esgPopulated : String?
    var marketState : String?
    var firstTradeDateMilliseconds : String?
    var priceHint : String?
    var preMarketTime : String?
    var preMarketPrice : String?
    var regularMarketTime : String?
    var regularMarketPrice : String?
    var fullExchangeName : String?
    var sourceInterval : String?
    var exchangeDataDelayedBy : String?
    var tradeable : String?
    var symbol : String?
}

here is my code at the JSONDecoder line it throw me to catch error

thank you


     let url = "https://query1.finance.yahoo.com/v7/finance/quote?lang=en-US&region=US&corsDomain=finance.yahoo.com&symbols=FB"
       
var quoteParent = QuoteParent()
        let req = AF.request(url, parameters: ["quoteResponse": "result"])
        req.responseData { (response) in
                guard let data = response.value else {return}
                do {
                    quoteParent = try JSONDecoder().decode(QuoteParent.self, from: data)
                    let stock = quoteParent.quoteResponse.result?[0]
                    let symbol = stock?.symbol?.uppercased() ?? ""
                    print(symbol)
                    
                    
                } catch {
                    print(error)
                }
        }
      
ozk
  • 1
  • 2
  • " it throw me to catch error" So what's the error? You have `print(error)`, so what's printing? – Larme May 05 '22 at 12:14
  • Unrelated, but since you have a Codable struct, why not use directly `responseDecodable()` instead of `responseData()`? – Larme May 05 '22 at 12:14
  • I didn't test your code with the params, since I don't know where to put the params (I guess it's a GET ?) Could you "print(String(data: data, encoding: .utf8))" ? – Larme May 05 '22 at 12:19
  • error DecodingError (0x8) – ozk May 05 '22 at 13:22
  • "Unrelated, but since you have a Codable struct, why not use directly responseDecodable() instead of responseData()?" --- can you provide a code line ? – ozk May 05 '22 at 13:23
  • In ` print(error)`, there should be a longer message explaining why the decoding failed. I tested your request without the `parameters` and it worked. `responseDecodable()` shouldn't fix your issue since the decoding is failing though. A little search: https://stackoverflow.com/questions/59342532/how-to-use-responsedecodable-method-in-alamofire – Larme May 05 '22 at 13:27
  • comment won't let me post the entier thing == String(data: data, encoding: .utf8) == "{\"quoteResponse\":{\"result\":[{\"language\":\"en-US\",\"region\":\"US\",\"quoteType\":\"EQUITY\",\"typeDisp\":\"Equity\",\"quoteSourceName\":\"Nasdaq Real Time Price\",\"triggerable\":true,\"customPriceAlertConfidence\":\"HIGH\",\"marketState\":\"PRE\",\"exchange\":\"NMS\",\"exchangeTimezoneName\":\"America/New_York\",\"exchangeTimezoneShortName\":\"EDT\",\"gmtOffSetMilliseconds\":-14400000,\"market\":\"us_market\",\"esgPopulated\":false,\"sourceInterval\":15,\"exchangeDataDelayedBy\":0,\"tradeable\":false – ozk May 05 '22 at 13:29
  • part 2 of == String(data: data, encoding: .utf8) == =====,\"priceHint\":2,\"preMarketTime\":1651757173,\"preMarketPrice\":218.0,\"regularMarketTime\":1651694404,\"regularMarketPrice\":223.41,\"fullExchangeName\":\"NasdaqGS\",\"firstTradeDateMilliseconds\":1337347800000,\"symbol\":\"FB\"}],\"error\":null}}" some – ozk May 05 '22 at 13:30
  • 1
    Edit your question with that instead... – Larme May 05 '22 at 13:30
  • Error = "The data couldn’t be read because it isn’t in the correct format." – ozk May 05 '22 at 13:38
  • That's `error.localizedDescripttion`, not `error`... – Larme May 05 '22 at 13:39
  • Error === "typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: \"quoteResponse\", intValue: nil), CodingKeys(stringValue: \"result\", intValue: nil), _JSONKey(stringValue: \"Index 0\", intValue: 0), CodingKeys(stringValue: \"triggerable\", intValue: nil)], debugDescription: \"Expected to decode String but found a number instead.\", underlyingError: nil))" – ozk May 05 '22 at 13:42
  • The error is saying that for `triggerable` you expected a `String` since you declared it like that:`var triggerable : String?`. But in fact, it's a bool: `"triggerable":true` in the JSON, not a String... – Larme May 05 '22 at 13:44

1 Answers1

0

Try to use responseDecodable instead,

  req.responseDecodable(of: QuoteParent.self) { response in
            let stock = response.value?.quoteResponse.result?[0]
            let symbol = stock?.symbol?.uppercased() ?? ""
            print(symbol)
  }

Declare the struct properties with the correct data type

struct Stock: Codable {
    var language : String?
    var region : String?
    var quoteType : String?
    var typeDisp : String?
    var quoteSourceName : String?
    var customPriceAlertConfidence : String?
    var exchange : String?
    var exchangeTimezoneName : String?
    var exchangeTimezoneShortName : String?
    var symbol : String?
    var market : String?
    var fullExchangeName : String?
    var marketState : String?
    var gmtOffSetMilliseconds : Double?
    var firstTradeDateMilliseconds : Double?
    var priceHint : Double?
    var preMarketTime : Double?
    var preMarketPrice : Double?
    var regularMarketTime : Double?
    var regularMarketPrice : Double?
    var sourceInterval : Double?
    var exchangeDataDelayedBy : Double?
    var tradeable : Bool?
    var esgPopulated : Bool?
    var triggerable : Bool?
}

And the result is "FB"

Mahmoud Eissa
  • 167
  • 1
  • 6
  • i changed the structure to the correct items === old see above and i made some changes to the code pls see above . but still same issue – ozk May 05 '22 at 12:58
  • i also tried the non optional change on my updates code above and it didn't work – ozk May 05 '22 at 13:07
  • responseDecodable didn't wok it jumped over it – ozk May 05 '22 at 13:21
  • @ozk I check your updates and I see and just declare all attributes as a string and as per API Response there are Strings, Ints , Double..etc So declare each property with the collect data type. – Mahmoud Eissa May 05 '22 at 13:29
  • ok i will try that – ozk May 05 '22 at 13:47
  • @ozk please check my edited answer. – Mahmoud Eissa May 05 '22 at 14:21
  • String(format: "%f", stock?.regularMarketPrice) but now it won't let me convert the double to string – ozk May 05 '22 at 14:22
  • Argument type 'Double?' does not conform to expected type 'CVarArg' – ozk May 05 '22 at 14:23
  • Yes i see, you ca use "\(stock?.regularMarketPrice)", or as an extension on Double extension Double { func string(style: NumberFormatter.Style) -> String { let formatter = NumberFormatter() formatter.numberStyle = style formatter.maximumFractionDigits = 2; return formatter.string(from: .init(value: self))! } } – Mahmoud Eissa May 05 '22 at 14:34
  • i used this :::::: NSDecimalNumber(decimal: Decimal(stock?.regularMarketPrice ?? 0)).stringValue – ozk May 05 '22 at 15:19
  • i also asked this few days ago with no luck ... https://stackoverflow.com/questions/72109327/in-xcode-how-can-i-show-local-notification-of-both-foreground-and-background-m – ozk May 05 '22 at 15:22