JSONEncoder issue?

I have a simple structure that will fill a list, this is later converted to json string. Once I convert the list to string, like:

let encoder = JSONEncoder() let data = try encoder.encode(myList) jsonString = String(data: data, encoding: .utf8)!)

It will convert as Json Array, but the issue is that the it can create more than one array into the string, such "[{key: value,key: value,key: value,key: value}] [{key: value,key: value}]" that second pair of array should not to be expected.

I've tried a lot of other examples and everything results in same, maybe its a string limitation, and the list itself isn't big.

I could generate the json string by myself, of course, however using the encoder should be enough.

Any clue?

Your post is really not clear and lacks a lot of information.

let encoder = JSONEncoder()
let data = try encoder.encode(myList)
jsonString = String(data: data, encoding: .utf8)!)
  • How is myList defined ?
  • How is the struct defined (probably named MyList)
  • Can you give an example ?

it can create more than one array into the string, such "[{key: value,key: value,key: value,key: value}] [{key: value,key: value}]"

Please show exactly what you get and what you expect.

Ok, this is my struct and the list, the real one:

struct Wifi: Codable {
    var SSID: String
    var bSSID: String
    var Channel: Int
    var Band: String
    var Width: String
    var noise: Int
    var rssi: Int
    var qualitySNR: Int
    var isConnected: Bool
    init() {
        SSID = ""
        bSSID = "00:00:00:00:00:00"
        Channel = 0
        Band = ""
        Width = ""
        rssi = 0
        noise = 0
        qualitySNR = 0
        isConnected = false
    }
}

var wifiList: [Wifi] = []

Here is how I do populate it:


wifiList.removeAll(keepingCapacity: false)

//... get all stuff from the network and insert into the list
// wifi is declared as  wifi = Wifi.init()
wifiList.insert(wifi, at: 0)

After the list if completed I convert it string, as I showed before:

func convertToJSONString() -> String {
    let encoder = JSONEncoder()
    let data = try! encoder.encode(wifiList)
    return String(data: data, encoding: .utf8)!
}

What I get:

[{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-77,"SSID":"CLARO_2GA37FE4","Channel":6,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-153},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-74,"SSID":"2.4G DEMOLIDOR HELMAR LUAN","Channel":8,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-150},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-88,"SSID":"TP-LINK_9562_5G","Channel":157,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-164},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-77,"SSID":"AP 71 A-5G","Channel":52,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-153},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-48,"SSID":"XIMA","Channel":157,"isConnected":true,"Width":"80MHz","noise":76,"qualitySNR":-124},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-83,"SSID":"5.G DEMOLIDOR HELMAR LUAN","Channel":48,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-159},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-61,"SSID":"LIMA_2G","Channel":10,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-137},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-76,"SSID":"Net-Virtua-9095-2.4G","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-152},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-84,"SSID":"#NET-CLARO-WIFI","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-160},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-91,"SSID":"Renato.2G","Channel":11,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-167},{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-78,"SSID":"AP 71 A","Channel":52,"isConnected":false,"Width":"80MHz","noise":76,"qualitySNR":-154},{"bSSID":"00:00:00:00:00:00","Band":"2Ghz","rssi":-85,"SSID":"Vila Mariana","Channel":1,"isConnected":false,"Width":"40MHz","noise":76,"qualitySNR":-161}] [{"bSSID":"00:00:00:00:00:00","Band":"5Ghz","rssi":-52,"SSID":"XIMA","Channel":157,"isConnected":false,"Width":"80MHz","noise":80,"qualitySNR":-132}]

In this example, the last item shouldn't be "out" of the array. The result shows like 2 arrays and I expect to have only one.

Why do you remove with

wifiList.removeAll(keepingCapacity: false)

and not just

wifiList.removeAll()

And could you also post the full code so that we can test ?

Can you show the full code between the convertToJSONString() call and the point where you (seem to) print the result to the console? Are there multiple threads/queues running this code simultaneously? Anything unusual at all?

If accurate, this suggests JSONEncoder is generating invalid JSON, and that’s not something I recall anyone ever reporting before. Very strange.

I will paste the full code, this is from Playground, now running on playground it won't separate the array, so I guess that can be related to the way I am doing in the real code, there it is called inside another function, so I think that I will enclosure it a thread and see what happens. The code below works fine.

Also, I know I can simply use wifiList.removeAll() instead of wifiList.removeAll(keepingCapacity: false), but as someone with little knowledgement in Swift I use that way to force me to learn about other options.

import Foundation
import CoreWLAN

class Discovery {

    var currentInterface: CWInterface
    var interfacesNames: [String] = []
    var networks: Set<CWNetwork> = []

    // Failable init using default interface
    init?() {
        if let defaultInterface = CWWiFiClient.shared().interface(),
              let name = defaultInterface.interfaceName {
            self.currentInterface = defaultInterface
            self.interfacesNames.append(name)
            self.findNetworks()
        } else {
            return nil
        }
    }

    init(interfaceWithName name: String) {
        self.currentInterface = CWWiFiClient().interface(withName: name)!
        self.interfacesNames.append(name)
        self.findNetworks()
    }

   // Fetch detectable WIFI networks
   func findNetworks() {
        do {
            self.networks = try currentInterface.scanForNetworks(withSSID: nil)
        } catch let error as NSError {
            print("Error: \(error.localizedDescription)")
        }
    }

}

struct Wifi: Codable {
    var SSID: String
    var bSSID: String
    var Channel: Int
    var Band: String
    var Width: String
    var noise: Int
    var rssi: Int
    var qualitySNR: Int
    var isConnected: Bool
    init() {
        SSID = ""
        bSSID = "00:00:00:00:00:00"
        Channel = 0
        Band = ""
        Width = ""
        rssi = 0
        noise = 0
        qualitySNR = 0
        isConnected = false
    }
}

var wifiList: [Wifi] = []
func getWifiNetworks()  {
    var connectedNetwork = ""
    wifiList.removeAll(keepingCapacity: false)
    if let discovery = Discovery() {
        
        var wifi: Wifi
        let connectedNetwork = CWWiFiClient.shared().interface()!.ssid()!
        for network in discovery.networks {
            wifi = Wifi.init()
            wifi.SSID = network.ssid?.description ?? ""
            wifi.isConnected = wifi.SSID == connectedNetwork
            wifi.bSSID = network.bssid?.description ?? "00:00:00:00:00:00"
            wifi.Channel = network.wlanChannel?.channelNumber ?? 0
            wifi.rssi = network.rssiValue
            wifi.noise = network.noiseMeasurement
            wifi.qualitySNR = wifi.rssi - wifi.noise
            
            switch network.wlanChannel?.channelBand {
            case .bandUnknown:
                wifi.Band = "Unknown"
            case .band2GHz:
                wifi.Band = "2Ghz"
            case .band5GHz:
                wifi.Band = "5Ghz"
            case .band6GHz:
                wifi.Band = "6Ghz"
            case .none:
                wifi.Band = "Unknown"
            case .some(_):
                wifi.Band = "Unknown"
            }
            
            switch network.wlanChannel?.channelWidth {
            case .width160MHz:
                wifi.Width = "160MHz"
            case .none:
                wifi.Width = "none"
            case .some(.widthUnknown):
                wifi.Width = "Unknown"
            case .some(.width20MHz):
                wifi.Width = "20MHz"
            case .some(.width40MHz):
                wifi.Width = "40MHz"
            case .some(.width80MHz):
                wifi.Width = "80MHz"
            case .some(_):
                wifi.Width = "Unknown"
            }
            wifi.rssi = network.rssiValue
            
            wifiList.insert(wifi, at: 0)
        }
    }
}

func convertWifiListToString() -> String {
    let encoder = JSONEncoder()
    let data = try! encoder.encode(wifiList)
    return String(data: data, encoding: .utf8)!
}

getWifiNetworks()
let wifiListJson = convertWifiListToString()
print(wifiListJson)

in the real code, there it is called inside another function

Which type of func is it ? If async, it could be a concurrency issue.

Which type of func is it ? If async, it could be a concurrency issue.

Yes, it is async and after reading some of your questions I refactored some parts and seems to be working now. Anyway it's one of the expected weird behaviors when not dealing well with threads.

Thank you guys!

JSONEncoder issue?
 
 
Q