swiftxcodedictionarypreview

Swift dictionary literal issue


Xcode is giving me this error:

Cannot convert value of type 'Match?' to expected element type 'Array.ArrayLiteralElement' (aka 'Match')

in the Preview on the line:

Match(dictionary: ["initiator": "a", "performer": "b"]),

When I try to insert couple of these guys of Match class type to the Preview:

import Foundation

class Match: Identifiable {
    public let id = UUID()
    public var initiator : String?
    public var performer : String?
    
    required public init?(dictionary: NSDictionary) {

        initiator = dictionary["initiator"] as? String
        performer = dictionary["performer"] as? String
    }
}

In my Preview of my view I have this:

#Preview {
    LatestMatchesView(matches: [

        Match(dictionary: ["initiator": "a", "performer": "b"]),
        Match(dictionary: ["initiator": "c", "performer": "d"])
    ])
}

This is the view code for the above Preview:

import SwiftUI

struct LatestMatchesView: View {
    @State var matches = [Match]()
    
    var body: some View {
        Text("LATEST MATCHES:")
            
        List(matches) { match in
            
            MatchListingView(match: match)
        }
        .onAppear {
            if ApiUtility.sharedInstance.isConnectedToNetwork() {
                let param : NSDictionary = [:]
                ApiUtility.sharedInstance.httpGet(url: WS_URL(url: LatestMatchesAPI), parameters:param) { (response, error) in
                    //self?.hideLoading()
                    if (error == nil) {
                        
                        self.manageResponse(r: response!)
                        
                    } else {
                        
                    }
                }
            }
        }
             
        Spacer()
            
    } // END var body
}

What am I missng here? I tried some things but none of them work.


Solution

  • The problem is that the initializer for Match is a “failable” initializer, which means that if the instance cannot be initialized for any reason, it will return nil. You can tell that the initializer is failable by the question mark after init.

    This means that the array literal you are passing to ListMatchView is Array<Match?> rather than Array<Match>. You can fix it quickly by compact mapping the array, which creates an array with only the non-optional values. For example:

    LatestMatchesView(matches: [
        Match(dictionary: ["initiator": "a", "performer": "b"]),
        Match(dictionary: ["initiator": "c", "performer": "d"])
    ].compactMap({ $0 }))
    

    Alternatively, if your app’s architecture allows it, you can convert the failable initializer to a normal initializer by removing the ? after init. If you do that, compact mapping is not necessary.