Search code examples
swiftfilterswiftuicodableswiftui-foreach

filter in ForEach based on id from another API SwiftUI


This is the struct having id and image url :

struct SampleImageLink:Codable{
    let success:Bool
    let message:String
    let linkResponse:[LinkResponse]
    
    enum CodingKeys: String, CodingKey{
        
        case success = "IsSuccess"
        case message = "Message"
        case linkResponse = "ResponseData"
    }
}


struct LinkResponse:Codable,Identifiable{
    
    var id:Int  
    let fileName:String

    //fileName is the link for image url and id is unique id associated with url

    enum CodingKeys: String, CodingKey{
        
        case id = "Id"
        case fileName = "FileName"
    }
    
}

Given below is the json response from another API

{
    "IsSuccess": true,
    "Message": "Data Returned",
    "ResponseData": [
        {
            "TestId": 681,
            "TestName": "Acidity Check Profile",
            "Type": "Package",
            "MRP": 0.0,
            "NetAmount": 0.0,
            "TestListForPackage": [
                {
                    "TestId": 274,
                    "TestName": "Sugar (Glucose) Fasting",
                    "TestCode": null,
                    "Type": null,
                    "MRP": 0.0,
                    "NetAmount": 0.0,
                    "TestPackageGroupId": null,
                    "MetabolitesList": [
                        {
                            "MetaboliteId": 820,
                            "MetaboliteName": "Glucose (Fasting)",
                            "TestName": null
                        }
                    ],
                    "TurnAroundTime": 4,
                    "TurnAroundTimeString": ""
                },
                {
                    "TestId": 1096,
                    "TestName": "Serum Electrolyte Profile",
                    "TestCode": null,
                    "Type": null,
                    "MRP": 0.0,
                    "NetAmount": 0.0,
                    "TestPackageGroupId": null,
                    "MetabolitesList": [
                        {
                            "MetaboliteId": 1117,
                            "MetaboliteName": "Chloride",
                            "TestName": null
                        },
                        {
                            "MetaboliteId": 1116,
                            "MetaboliteName": "Potassium",
                            "TestName": null
                        },
                        {
                            "MetaboliteId": 1115,
                            "MetaboliteName": "Sodium",
                            "TestName": null
                        }
                    ],
                    "TurnAroundTime": 4,
                    "TurnAroundTimeString": ""
                },
              ],
            "SampleTypeList": [
                {
                    "TestSampleTypeId": "51",
                    "SampleName": "Fluoride Plasma - F",
                    "PackageId": 681,
                    "PackageName": null
                    
                },
                {
                    "TestSampleTypeId": "55",
                    "SampleName": "EDTA Whole Blood",
                    "PackageId": 681,
                    "PackageName": null
                    
                },
                {
                    "TestSampleTypeId": "50",
                    "SampleName": "Serum",
                    "PackageId": 681,
                    "PackageName": null
                   
                }
            ]
        }
    ]
}

Below is the struct for above json.

struct PriceDetailResponse:Codable{

let success:Bool
let message:String
let response:[DetailResponse]

enum CodingKeys: String, CodingKey{
    
    case success = "IsSuccess"
    case message = "Message"
    case response = "ResponseData"
}}

struct DetailResponse:Codable, Identifiable{
    
    var id: Int{testId}
    let testId:Int
    //define items
    let testPackage:[TestListPackage]
    let sampleType:[SampleList]
    
    enum CodingKeys: String, CodingKey{
        
        case testId = "TestId"
       //define items
        case testPackage = "TestListForPackage"
        case sampleType = "SampleTypeList"
    }
}

struct TestListPackage:Codable{
    
    //define all items
    let metabolite : [Metabolites]
    
    enum CodingKeys: String, CodingKey{
        
        case metabolite = "MetabolitesList"
        
    }
}

struct Metabolites:Codable{
    //define items
}

struct SampleList:Codable, Identifiable{
    var id:Int{packageId}
    
    let testSampleTypeId : String
    let sampleName : String
    let packageId : Int
    let packageName : String?
   
    
    enum CodingKeys: String, CodingKey{
        
        case testSampleTypeId = "TestSampleTypeId"
        case sampleName = "SampleName"
        case packageId = "PackageId"
        case packageName = "PackageName"
       
    }
}

All is working fine. I have also displayed images using UIImage and Asyncimage. However, the requirement is image should be displayed if

Id from SampleImageLink struct == TestSampleTypeId of SampleList struct

I have created a view to display images, now need to filter the ids so that only the above matching id images should display

for eg:

ForEach(imgModel.link.filter{$0.id == 51}){img in
                        ImageLoader(urlString: img.fileName)
                   }
//imgModel is the ImageViewModel object.

is working fine. But how to iterate over SampleList and match with id of image What is the way to do it (id in SampleImageLink is int whereas in SampleList, testSampleTypeId is string).


Solution

  • One approach could be to cast testSampleTypeId to an Int while decoding. This way you can compare to it in the ForEach loop:

    struct SampleList:Codable, Identifiable{
        var id:Int{packageId}
        
        let testSampleTypeId : Int
        let sampleName : String
        let packageId : Int
        let packageName : String?
       
        
        enum CodingKeys: String, CodingKey{
            
            case testSampleTypeId = "TestSampleTypeId"
            case sampleName = "SampleName"
            case packageId = "PackageId"
            case packageName = "PackageName"
           
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            
            sampleName = try container.decode(String.self, forKey: .sampleName)
            packageId = try container.decode(Int.self, forKey: .packageId)
            packageName = try container.decodeIfPresent(String.self, forKey: .packageName)
            // decode to a String, cast it to an Int and check if successfull; else throw error
            guard let testSampleTypeId = Int(try container.decode(String.self, forKey: .testSampleTypeId)) else{
                throw DecodingError.dataCorrupted(.init(codingPath: [CodingKeys.testSampleTypeId], debugDescription: "TestSampleTypeId could not be casted to type Int"))
            }
            
            self.testSampleTypeId = testSampleTypeId
        }
        
    }