-1

I sure would appreciate some assistance. I'm using Swift 5.1. What I'm attempting is to get the current date (date4) and format it to a three letter month abbreviation. No issue that part works fine. Then I define a constant called (currentMonthDate) that holds the concatenation of the three letter month and the string "MoonData". The result looks like this: "FebMoonData" - Up to this point all works as designed.

My Json is separated by month. Shown below is two months worth of Json as an abbreviated example. Obviously my model is designed to to accommodate the Json structure - not included. Now the issue. If you look at the JSONDecoder line of code you'll notice that I'm attempting to use the concatenation string "currentMonthDate" in the decoder line of code. My thought being that as each new month arrives data4 will be change and currentMonthDate will reflect that change and will then find the JSON block of data that reflects that particular month. The error I'm receiving is: Cannot convert value of type 'String' to expected argument type 'Data' For the sake of clarity if I simply type FebMoonData (name of the Json block for Feb) in the decoder line it works as expected. That is, it finds the Json array titled FebMoonData. Thank you!

// JSON

let FebMoonData = """
[

{"time":"20 Feb 2020 00:00 UT"}

]
""".data(using: .utf8)!

let MarMoonData = 
[

{"time":"20 Feb 2020 00:00 UT"}

]

""".data(using: .utf8)!

// End JSON


 let date4 = Date()
        let dateFormatterGet = DateFormatter()
        dateFormatterGet.dateFormat = "MMM"
        let currentMonthDate = dateFormatterGet.string(from: date4) + "MoonData"


        let moonphase = try! JSONDecoder().decode([MoonPhase].self, from: currentMonthDate)
skybox
  • 15
  • 6
  • 2
    The leading `"""` for the string literal after `let MarMoonData =` is missing. – Martin R Feb 26 '20 at 19:57
  • Show your `MoonPhase` declaration. Btw your `currentMonthDate` it is not a valid JSON array. Please take a look at how to provide a [mcve] – Leo Dabus Feb 26 '20 at 20:07

1 Answers1

0

The from parameter of decode must be Data, not String, this is the message of the error. The literal date string as JSON data makes no sense anyway. It's impossible to compose variable names at runtime.

What you can do is

let month = Calendar.current.component(.month, from: Date())

let data : Data
switch month {
   case 1: data = Data(JanMoonData.utf8)
   case 2: data = Data(FebMoonData.utf8)
   // ...
}

let moonphase = try! JSONDecoder().decode([MoonPhase].self, from: data)

or

let month = Calendar.current.component(.month, from: Date())

let moonJSON : String
switch month {
   case 1: moonJSON = JanMoonData
   case 2: moonJSON = FebMoonData
   // ...
}

let moonphase = try! JSONDecoder().decode([MoonPhase].self, from: Data(moonJSON.utf8)

or

let moonJSONArray = [JanMoonData, FebMoonData, MarMoonData, ..., DecMoonData]
let month = Calendar.current.component(.month, from: Date())
let moonJSON = moonJSONArray[month - 1]
let moonphase = try! JSONDecoder().decode([MoonPhase].self, from: Data(moonJSON.utf8)
vadian
  • 274,689
  • 30
  • 353
  • 361
  • I understand your answer to a certain degree but still running into an issue. First, since the Json structure is already being designed as "utf8" do I still need the extension in the case statement? Also, I'm getting an error stating: "Constant 'data' used before being utilized." I'm assuming ... data = Data(FebMoonData) ... is returning the JSON value into the "data" variable of type Data, correct? So if that's the case then why the error? Thank you – skybox Feb 27 '20 at 17:09
  • You get the error because the `switch` is not exhaustive. Instead of `case 12` for the last case write `default: data = Data(DecMoonData.utf8)`, this fixes the error. Yes, you need `.utf8` for the conversion. But you can also declare a `String` variable and convert it to `Data` once at the end. I just wanted to show you one way, there are several. – vadian Feb 27 '20 at 17:14
  • I really appreciate you taking the time to help. I'm now receiving this error: Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Badly formed array around character 178102." UserInfo={NSDebugDescription=Badly formed array around character 178102.}))) – skybox Feb 27 '20 at 18:34
  • Interestingly, if I just use "FebMoonData" in the decoder line it works fine but for some reason it doesn't like the info its getting from moonJSNArray or the other suggestions you provided. – skybox Feb 27 '20 at 18:43
  • Also when I attempt to use .utf8 at the end of moonJSON i get an error stating "Value of type Data has no member .utf8" – skybox Feb 27 '20 at 18:59
  • The error *Badly formed array around character 178102* is pretty clear. The JSON is corrupted. It seems that you are receiving data about the entire solar system . Each of my suggestions work with the rudimentary JSON in the question – vadian Feb 27 '20 at 22:32
  • Lol I agree. Actually there is a fair amount of data in the JSON - hence why I chose to break it down into months. With respect to the error what’s strange if I simply put “JanMoonData” into the decoder line the app works perfect. So that tells me the data isn’t corrupt. It doesn’t make sense because each of the array items represents one month of JSON data. So when that item is put into the decoder I don’t know why it won’t work. Also, I get an error concerning the utf8 extension stating it doesn’t exist for the data. I used your examples literally. – skybox Feb 27 '20 at 23:38