Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))

I want to get the information of the networks list and decode it but I failed,

💥 fetchNetworks() typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))

My Json Data look like this,

  {  "networks" : [{

  "isSplit" : true,

  "securityMode" : "WPA2_PSK",

  "ssid" : "Guest5531FC",

  "frequencyBand" : "5_GHZ",

  "enabled" : true,

  "connectedDevices" : 0,

  "isGuest" : true,

  "password" : "Admin@123",

  "isBackhaul" : false,

  "visible" : true,

  "id" : "@cred4"

},

{

  "isSplit" : true,

  "securityMode" : "NONE",

  "ssid" : "Office_telco",

  "frequencyBand" : "2_4_GHZ",

  "enabled" : true,

  "connectedDevices" : 0,

  "isGuest" : false,

  "password" : "Admn@234",

  "isBackhaul" : false,

  "visible" : true,

  "id" : "@cred0"

}]}

My Source Code is like,

import Foundation

struct WanNetworks: Codable, Equatable {
    
    let networks: [Networks]

}

import Foundation
struct Networks: Codable, Equatable {
    
    let connectedDevices: Int
    let id: String
    let enabled: Bool
    let visible: Bool
    let isGuest: Bool
    let ssid: String
    let bssid: String?
    let frequencyBands: String?
    let isBackhaul: Bool
    let frequencyBand: String
    let password: String?
    let securityMode: String
    let isSplit: Bool
    
}

import Foundation

/// The serializer is responsible for generating the response that is returned by the service request.
public protocol Serializer {
    /// The response returned by the `execute`'s `completion` handler.
    associatedtype Response
    
    
    /// - returns: A generic response defined by the implementation class.
    func serialize(data: Data?, error: Error?, response: HTTPURLResponse?) -> Response
}

import Foundation

public struct CodableSerializer<Model: Codable>: Serializer {

    // MARK: - Internal

    private var decoder: JSONDecoder

    // MARK: - Init

    public init(decoder: JSONDecoder = JSONDecoder()) {
        self.decoder = decoder
    }
    
    // MARK: - Response
    
    /// The codable response returned by the `CodableSerializer`.
    public enum Response {
        /// When data is correctly parsed we return the `Codable` instance. This can also be nil when no
        /// data was returned.
        case success(Model?)
        /// Failure is triggered an error is returned or when parsing the data didn't succeed.
        case failure(Error)
    }
    
    // MARK: - Serialize
    
    public func serialize(data: Data?, error: Error?, response: HTTPURLResponse?) -> CodableSerializer<Model>.Response {
        // When an error occurs we return this error.
        if let error = error { return .failure(error) }
        
        // When a status code larger or equal than 400 is returned we return a custom error.
        if
            let response = response,
            let responseError = ResponseError(statusCode: response.statusCode) {
            print(response.statusCode)
            return .failure(responseError)
        }
        
        /// When no data object (or an empty one) is returned from the server we have a successful.
        guard
            let data = data,
            !data.isEmpty else { return .success(nil) }
            print("datas is ",data)
        do {
            print(Model.self)
            let result = try decoder.decode(Model.self, from: data)
            return .success(result)
        } catch {
            return .failure(error)
        }
    }
    
    
}

Xcode always giving me the error "Expected to decode Array but found a dictionary instead". I don't understand what it mean here. More precisely, I did not understand what to do. I used the same code to pull other information from JSON and it worked there. I looked at the answers to the questions asked under this title before, but I could not get an answer to my question. How can I fix this?

You don't show a call-site where serialize(data:error:response) is called, and that's probably where the issue arises.

It looks like you done something non-recommended in your CodableSerializer type. None of its functions (including the initializer) takes a parameter involving the generic type Model, so type inference is apparently going to have to infer the generic type from the return type of that function. In general, it's recommended that you don't do this in Swift, because it's too easy to under-constrain the inference.

My guess is that your call site doesn't provide enough information for the generic parameter to inferred correctly, and that's what is leading to this error.

Here I adding the entire part of serialize(data:error:response) calling, it looks like below source code.


class NetworkService: NSObject {
    
    // MARK: - Internal
    
    private let configuration: Configuration
    private let pinningService: PublicKeyPinningService
    
    // MARK: - Init
    
    init(configuration: Configuration, pinningService: PublicKeyPinningService) {
        self.configuration = configuration
        self.pinningService = pinningService
    }
    
    // MARK: - Execute
    
    @discardableResult
    // swiftlint:disable function_parameter_count
    func execute<S: Serializer>(_ urlRequest: URLRequest,
                                with serializer: S,
                                isInterceptable: Bool,
                                retryCount: UInt,
                                executionQueue: DispatchQueue?,
                                retry: @escaping () -> Void,
                                completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask {
        // Trigger the loggers before the request is done.
        configuration.start(urlRequest: urlRequest)
        // Prepare the session.
        let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
        // Execute the task.
        let task = session.dataTask(with: urlRequest) { [weak self] data, urlResponse, error in
            /// When the url response has a response error and an interceptor is set we check if the request flow
            /// should be stopped.
            if
                let responseError = urlResponse?.responseError,
                let interceptor = self?.interceptor,
                isInterceptable,
                interceptor.intercept(responseError, data: data, retryCount: retryCount, retry: retry) {
                return
            }
            
            let responseError: Error? = error ?? urlResponse?.responseError
            let response = serializer.serialize(data: data,
                                                error: responseError,
                                                response: urlResponse as? HTTPURLResponse)
            // Make sure the completion handler is triggered on the same queue as the `execute` was triggered on.
            self?.complete(on: executionQueue, block: { completion(response) })
        }
        task.resume()
        // This causes the delegate to be released correctly.
        session.finishTasksAndInvalidate()
        return task
    }
    
    // MARK: - Retry
    
    var interceptor: Interceptor?
    
    // MARK: - Helpers
    
    /// Perform the block on the given queue, when no queue is given we just execute the block.
    private func complete(on queue: DispatchQueue?, block: @escaping () -> Void) {
        guard let queue = queue else {
            block()
            return
        }
        queue.async(execute: block)
    }
}

extension NetworkService: URLSessionDataDelegate {
    func urlSession(_ session: URLSession,
                    didReceive challenge: URLAuthenticationChallenge,
                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        let host = challenge.protectionSpace.host
        guard
            let serverTrust = challenge.protectionSpace.serverTrust,
            challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        
        pinningService.handle(serverTrust, host: host, completionHandler: completionHandler)
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
        guard
            let urlRequest = task.currentRequest,
            let urlResponse = task.response else { return }
        
        // Trigger the loggers when the request finished.
        configuration.end(urlRequest: urlRequest,
                          urlResponse: urlResponse,
                          metrics: metrics,
                          error: task.error ?? urlResponse.responseError)
    }
}

Below adding the Network Configuration Source Code.

import Foundation

/// This it the main executor of requests.
open class Service {
    
    // MARK: - Internal
    
    private let configuration: Configuration
    private let networkService: NetworkService
    
    // MARK: - Init
    
    /// Initialize the Service layer.
    ///
    /// - parameter configuration: Configure the service layer through this instance.
    public init(configuration: Configuration) {
        self.configuration = configuration
        self.networkService = NetworkService(configuration: configuration,
                                             pinningService: PublicKeyPinningService(configuration: configuration))
    }
    
    // MARK: - Execute
    
    /// Execute the given request and get an appropriate response returned.
    ///
    /// ```swift
    /// let request = SomeRequest()
    /// let serializer = SomeSerializer()
    /// service.execute(request, with: serializer) { response in
    ///    ...
    /// }
    /// ```
    ///
    /// - parameter request: The request to execute.
    /// - parameter serializer: The result of the request will go through serialization.
    /// - paremeter completion: The block that is triggered on completion.
    ///
    /// - returns: The executed data task.
    @discardableResult
    public func execute<S: Serializer>(_ request: Request,
                                       with serializer: S,
                                       completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? {
        // Get the originating queue.
        let executionQueue: DispatchQueue? = OperationQueue.current?.underlyingQueue
        return execute(request, with: serializer, retryCount: 0, executionQueue: executionQueue, completion: completion)
    }

    /// This private function is used just to keep track of the retry count of the current request.
    @discardableResult
    private func execute<S: Serializer>(_ request: Request,
                                        with serializer: S,
                                        retryCount: UInt,
                                        executionQueue: DispatchQueue?,
                                        completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? {
        do {
            // Create the request.
            let urlRequest = try request.makeURLRequest(with: configuration)
            return networkService.execute(urlRequest,
                                          with: serializer,
                                          isInterceptable: request.isInterceptable,
                                          retryCount: retryCount,
                                          executionQueue: executionQueue,
                                          retry: { [weak self] in
                self?.execute(request,
                              with: serializer,
                              retryCount: retryCount + 1,
                              executionQueue: executionQueue,
                              completion: completion)
            }, completion: completion)
        } catch {
            let response = serializer.serialize(data: nil, error: error, response: nil)
            completion(response)
            return nil
        }
    }
    
    // MARK: - Interceptor
    
    /// Define the interceptor. This can be usefull when you want to handle some status code
    /// differently.
    /// ex. refresh, maintenance mode, ...
    public var interceptor: Interceptor? {
        set { networkService.interceptor = newValue }
        get { return networkService.interceptor }
    }
}
Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array&lt;Any&gt; but found a dictionary instead.", underlyingError: nil))
 
 
Q