Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can you pass the name of a property to a function in Swift?

I have a struct containing a bunch of properties referencing different types of statistics. A sample object is:

class Stats {
    stats: [Stat]
}
struct Stat {
    id: UUID
    countA: Int
    countB: Int
    countC: Int
    totalAAttempts: Int
    totalBAttempts: Int
    totalCAttempts: Int
    ...
}

I am displaying the percentages with a bunch of functions in the class…

class Stats {
    stats: [Stat]
    var countAPerc: Double {
        let totalA = stats.reduce(0) { total, stat in
            total + stat.countA
        }
        let totalAttemps = s.reduce(0) { total, stat in
            total + stat.totalAAttempts
        }
        return Double(totalA) / Double(totalAttempts)
    }
    var: countAPercDisplay: String {
        String(format: "%.1f", countAPerc * 100) + "%"
    }
    var countBPerc: Double {
        let totalB = stats.reduce(0) { total, stat in
            total + stat.countB
        }
        let totalAttemps = s.reduce(0) { total, stat in
            total + stat.totalBAttempts
        }
        return Double(totalB) / Double(totalAttempts)
    }
    var: countBPercDisplay: String {
        String(format: "%.1f", countBPerc * 100) + "%"
    }
    ...
}

Is it possible to specify the name of the property as a parameter in a function to prevent the same code from being written over and over? Something like:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

func summarizeProperty(_ countProperty: PROPERTYNAME1, _ totalProperty: PROPERTYNAME2) -> Double {
    let totalCount = stats.reduce(0) { total, stat in
        total + stat.PROPERTYNAME1
    }
    let totalAttemps = s.reduce(0) { total, stat in
        total + stat.PROPERTYNAME2
    }
    return Double(totalCount) / Double(totalAttempts)
}

func summarizedProperty(_ countProperty: PROPERTYNAME1, _ totalProperty: PROPERTYNAME2) -> String {
    let summarized = summarizeProperty(PROPERTYNAME1, PROPERTYNAME2)
    return String(format: "%.1f", summarized * 100) + "%"
}

And then call it…

Text(summarizedProperty(countA, totalAAttempts))

Thanks in advance

>Solution :

The tool you want here is a KeyPath:

func summarizeProperty(_ countProperty: KeyPath<Stat, Int>, _ totalProperty: KeyPath<Stat, Int>) -> Double {
    let totalCount = stats.reduce(0) { total, stat in
        total + stat[keyPath: countProperty]
    }
    let totalAttempts = stats.reduce(0) { total, stat in
        total + stat[keyPath: totalProperty]
    }
    return Double(totalCount) / Double(totalAttempts)
}

A KeyPath<Stat, Int> is property on Stat that returns an Int. It is accessed using the keyPath: subscript and generally created using the \ syntax :

Stats().summarizeProperty(\.countA, \.totalAAttempts)

KeyPaths are normal values and can be passed around like this:

func summarizedProperty(_ countProperty: KeyPath<Stat, Int>, _ totalProperty: KeyPath<Stat, Int>) -> String {
    let summarized = summarizeProperty(countProperty, totalProperty)
    return String(format: "%.1f", summarized * 100.0) + "%"
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading