UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Using reduce(_:_:) to calculate savings balance year after year

Forums > Swift

I am having trouble printing the balance of a savings account for each future year. I am working within the framework of code which is functional in calculating deposits into a savings account each year.


enum Calculations {
    private static let pennyRoundingBehavior = NSDecimalNumberHandler(
        roundingMode: .bankers,
        scale: 2,
        raiseOnExactness: false,
        raiseOnOverflow: true,
        raiseOnUnderflow: true,
        raiseOnDivideByZero: true
    )
    static func computeMonthlyEarnings(hours hoursWorked: Int, atPayRate payRate: Int) -> Decimal {
        let base = Decimal(hoursWorked * payRate) as NSDecimalNumber
        return base.rounding(accordingToBehavior: pennyRoundingBehavior) as Decimal
    }
    static func computeMonthlySavings(hours hoursWorked: Int, atPayRate payRate: Int, percentSaved percent: Double) -> Decimal {
        let base = Decimal(hoursWorked * payRate) * Decimal(percent / 100.0) as NSDecimalNumber
        return base.rounding(accordingToBehavior: pennyRoundingBehavior) as Decimal
    }
}

extension Array {
    func chunked(into size: Int) -> [[Element]] {
        return stride(from: 0, to: count, by: size).map {
            Array(self[$0 ..< Swift.min($0 + size, count)])
        }
    }
}
enum Department: RawRepresentable {
    case sales
    case management
    case seniorManagement
    case other(String)

    init?(rawValue: String) {
        switch rawValue {
        case "Sales": self = .sales
        case "Management": self = .management
        case "Senior Management": self = .seniorManagement
        case let dept: self = .other(dept)
        }
    }
    var rawValue: String {
        switch self {
        case .sales: return "Sales"
        case .management: return "Management"
        case .seniorManagement: return "Senior Management"
        case .other(let dept): return dept
        }
    }
    func payRate(forYearsWorked numberOfYears: Int) -> Int {
        let rates: [Int]
        switch self {
        case .sales: rates = [20,22,24,26,28,30,32,34,36,38,40]
        case .management: rates = [30,32,34,36,38,40,42,44,46,48,50]
        case .seniorManagement: rates = [40,42,44,46,48,50,52,54,56,58,60]
        default: rates = [10,12,14,16,18,20,22,24,26,28,30]
        }
        return rates[min(numberOfYears, rates.count) - 1]
    }
}

struct Employee {
    let name: String
    var birthdate: Date
    var hiredate: Date
    var retirementAge: Int
    var department: Department
    var monthlyHoursWorked: Int
    var percentToSave: Double
    var percentToRoth: Double
    var percentToTrad: Double

    private(set) var employmentHistory: [Department]

    init(_ name: String,
         birthdate: Date,
         hiredate: Date,
         retirementAge: Int,
         department: Department = .other("Employee"),
         monthlyHoursWorked: Int,
         percentToSave: Double,
         percentToRoth: Double,
         percentToTrad: Double)
    {
        self.name = name
        self.birthdate = birthdate
        self.hiredate = hiredate
        self.retirementAge = retirementAge
        self.department = department
        self.monthlyHoursWorked = monthlyHoursWorked
        self.percentToSave = percentToSave
        self.percentToRoth = percentToRoth
        self.percentToTrad = percentToTrad
        self.employmentHistory = []
    }
}

extension Employee {
    mutating func promote(to newDepartment: Department) {
        department = newDepartment
    }
    mutating func work(months: Int) {
        employmentHistory
            .append(contentsOf: Array.init(repeating: department,
                                           count: months))
    }
    mutating func work(years: Int) {
        work(months: years * 12)
    }
    mutating func work(years: Int, months: Int) {
        work(months: years * 12 + months)
    }
    func yearlyEarnings() -> [Decimal] {
        let years = employmentHistory.chunked(into: 12)
        var earnings: [Decimal] = []
        for (index, months) in years.enumerated() {
            let yearEarnings: Decimal = months.reduce(0) { runningTotal, dept in
                let payRate = dept.payRate(forYearsWorked: index + 1)
                let monthlyEarnings = Calculations.computeMonthlyEarnings(
                    hours: monthlyHoursWorked,
                    atPayRate: payRate
                )
                return runningTotal + monthlyEarnings
            }
            earnings.append(yearEarnings)
        }
        return earnings
    }
    func yearlySavings() -> [Decimal] {
        let years = employmentHistory.chunked(into: 12)
        var savings: [Decimal] = []
        for (index, months) in years.enumerated() {
            let yearSavings: Decimal = months.reduce(0) { runningTotal, dept in
                let payRate = dept.payRate(forYearsWorked: index + 1)
                let monthlySavings = Calculations.computeMonthlySavings(
                    hours: monthlyHoursWorked,
                    atPayRate: payRate,
                    percentSaved: percentToSave
                )
                return runningTotal + monthlySavings
            }
            savings.append(yearSavings)
        }
        return savings
    }    
    //<- add cumulative savings function here
}

extension Employee {
    func yearlyDepartments() -> [String] {
        let years = employmentHistory.chunked(into: 12)
        let departments: [String] = years.map { months in
            var seenDepts: Set<String> = []
            return months.reduce(into: [String]()) { acc, dept in
                if seenDepts.insert(dept.rawValue).inserted {
                    acc.append(dept.rawValue)
                }
            }.joined(separator: ",") //concat the final result with , separator
        }
        return departments
    }
    func yearlyDepartmentsEarningsAndSavings() -> [(String, (Decimal, Decimal))] {
        let yearlyDepartments = yearlyDepartments()
        let yearlyEarnings = yearlyEarnings()
        let yearlySavings = yearlySavings()
        let yearlyDepartmentsEarningsAndSavings: [(departments: String, (earnings: Decimal, savings: Decimal))] =
            Array(zip(yearlyDepartments, zip(yearlyEarnings, yearlySavings)))
        return yearlyDepartmentsEarningsAndSavings
    }
}

var birthdate = DateComponents(calendar: .current, year: 1965, month: 7, day: 20).date!
var hiredate = DateComponents(calendar: .current, year: 2021, month: 12, day: 28).date!
var promotion1date = DateComponents(calendar: .current, year: 2023, month: 12, day: 28).date!
var firstDeptMonths: Int { Calendar.current.dateComponents([.month], from: hiredate, to: promotion1date).month! }
var promotion2date = DateComponents(calendar: .current, year: 2025, month: 6, day: 28).date!
var secondDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion1date, to: promotion2date).month! }
var promotion3date = DateComponents(calendar: .current, year: 2026, month: 12, day: 28).date!
var thirdDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion2date, to: promotion3date).month! }
var retireAge = 65
let retireDate = Calendar.current.date(byAdding: .year, value: retireAge, to: birthdate)!
var fourthDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion3date, to: retireDate).month! }

extension Date {
    var age: Int { Calendar.current.dateComponents([.year], from: self, to: Date()).year! }

    var yearGroup: Int { Calendar.current.dateComponents([.year], from: self, to: Date()).year! + 1}

    var totalYearsRemaining: Int { Calendar.current.dateComponents([.year], from: self, to: retireDate).year! }

    var totalMonthsRemaining: Int { Calendar.current.dateComponents([.month], from: self, to: retireDate).month! }
}
//age
let age = birthdate.age
//number of years employee has worked for the company
let yearGroup = hiredate.yearGroup

func printYearlyDepartmentsAndEarnings(_ yearlyDeptsAndEarnings: [(departments: String, (earnings: Decimal, savings: Decimal))]) {
    for (year, deptsAndEarnings) in yearlyDeptsAndEarnings.enumerated() {
        print("Department(s) for Year \(year + yearGroup + 1): \(deptsAndEarnings.departments)")
        print("Earnings for Year \(year + yearGroup + 1): \(deptsAndEarnings.1.earnings)")
        print("Savings for Year \(year + yearGroup + 1): \(deptsAndEarnings.1.savings)")
        print("Age: \(year + age)")
        print("")
    }
}
func printSavingsBalance(_ savingsBalance: [(Decimal)]) {
    for (year, save) in savingsBalance.enumerated() {
        print("Savings Balance Year \(year + yearGroup + 1): \(save)")
    }
}
//create a new employee
var charlotte = Employee("Charlotte Grote", birthdate: birthdate, hiredate: hiredate, retirementAge: 65, department: .other("Hospitality"), monthlyHoursWorked: 160, percentToSave: 10.0, percentToRoth: 10.0, percentToTrad: 16.0)
//give our employee some work history
//months in Hospitality
charlotte.work(months: firstDeptMonths)
//ohh, a promotion!
charlotte.promote(to: .sales)
//months in Sales
charlotte.work(months: secondDeptMonths)
//another promotion. way to go, Charlotte!
charlotte.promote(to: .management)
//months in Management
charlotte.work(months: thirdDeptMonths)
//another promotion. way to go, Charlotte!
charlotte.promote(to: .seniorManagement)
//months in Senior Management
charlotte.work(months: fourthDeptMonths)
//how much money has Charlotte made after all this time?
printYearlyDepartmentsAndEarnings(charlotte.yearlyDepartmentsEarningsAndSavings())

The above code is functional but when I add in the following function below func yearlySavings, the build fails without an error (debugger is empty):

func cumulativeSavingsSinceFirstHired() -> [Decimal] {
        let years = employmentHistory.chunked(into: 12)
        var savings: [Decimal] = []
        var cumulativeSavings: [Decimal] = []
        for (index, months) in years.enumerated() {
            let yearSavings: Decimal = months.reduce(0) { runningTotal, dept in
                let payRate = dept.payRate(forYearsWorked: index + 1)
                let monthlySavings = Calculations.computeMonthlySavings(
                    hours: monthlyHoursWorked,
                    atPayRate: payRate,
                    percentSaved: percentToSave
                )
                return runningTotal + monthlySavings
            }
            savings.append(yearSavings)
        }
        let currentTotalSavings: Decimal = savings.reduce(0) {partialResult,_ in
            return
        }
        cumulativeSavings.append(currentTotalSavings)
        return cumulativeSavings
    }

2      

Just to clarify, when you say cumulative savings, you want to end up with a result like this:

//given n years of work history...

[
    year 1,
    year 1 + year 2,
    year 1 + year 2 + year 3,
    year 1 + year 2 + year 3 ... + year n
]

Is that correct?

2      

That is correct :)

2      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Here's one way you could do it:

extension Employee {
    func cumulativeSavingsSinceFirstHired() -> [Decimal] {
        //get our savings amount for each year of employment
        let savingsByYear = yearlySavings()

        //create an array to hold the cumulative savings for each year
        //we initialize each slot as 0
        //this saves us having to do a bunch of appends
        var cumulativeSavings: [Decimal] = .init(repeating: .zero, count: savingsByYear.count)

        //now loop through the yearly savings
        for idx in savingsByYear.indices {
            //and use reduce on a slice of the array from the startIndex (i.e., 0)
            //  to the current idx
            //so 0...0, then 0...1, then 0...2, etc
            cumulativeSavings[idx] = savingsByYear[0...idx].reduce(0) { accum, yrAmount in
                //simply add the cumulative total and the amount for the year
                accum + yrAmount
            }
        }

        //send it back out
        return cumulativeSavings
    }
}

There are other ways, but I find this to be probably the easiest because you don't have to track indices in multiple arrays and such. A problem with this approach is that you iterate through the array many times, albeit not all of the iterations have the same length. Probably not too big a deal given that you wouldn't expect an employee to have more than a few dozen years of work experience, but still something to consider.

An interesting way to do it but one I find kind of hard to read and reason about at first glance is this:

extension Employee {
    func cumulativeSavingsSinceFirstHired() -> [Decimal] {
        //get our savings amount for each year of employment
        let savingsByYear = yearlySavings()

        //feed each year into an array and add it to the value of the array's last item, if it exists,
        //  or 0 if it does not (which takes care of the first year's amount)
        let cumulativeSavings: [Decimal] = savingsByYear.reduce(into: []) { accum, yrAmount in
            accum.append((accum.last ?? 0) + yrAmount)
        }

        //send it back out
        return cumulativeSavings
    }
}

3      

@roosterboy

Thank you for your help!

I've pressed forward onto the next phase which includes calculating the compound interest of roth 401k investments. Here is the general formula for 401k growth:

func calc401k(princ: Decimal, deposits: Decimal, rate401k: Decimal) -> Decimal {
        let rn1 = 1+((rate401k/100)/12)
        let comp = pow(rn1,12)
        let totPrinc = comp * princ
        return totPrinc + ((deposits/12) * (comp-1)/((rate401k/100)/12))
    }

I've applied principles from the yearlySavings function to calculate an employee's regular deposit into his 401k:

 static func computeMonthlyRoth(hours hoursWorked: Int, atPayRate payRate: Int, percentToRoth percent: Double) -> Decimal {
        let base = Decimal(hoursWorked * payRate) * Decimal(percent / 100.0) as NSDecimalNumber
        return base.rounding(accordingToBehavior: pennyRoundingBehavior) as Decimal
    }

    ...

    func depositsToRoth() -> [Decimal] {
        let years = employmentHistory.chunked(into: 12)
        var toRoth: [Decimal] = []
        for (index, months) in years.enumerated() {
            let yearToRoth: Decimal = months.reduce(0) { runningTotal, dept in
                let payRate = dept.payRate(forYearsWorked: index + 1)
                let monthlyToRoth = Calculations.computeMonthlyRoth(
                    hours: monthlyHoursWorked,
                    atPayRate: payRate,
                    percentToRoth: percentToRoth
                )
                return runningTotal + monthlyToRoth
            }
            toRoth.append(yearToRoth)
        }
        return toRoth
    }

It is after this that I am getting stuck. Here is my attempt to use the calc401k formula to calculate a yearly 401k balance:

func balanceRoth(princ: Decimal, rate401k: Decimal) -> [Decimal] {
        let years = employmentHistory.chunked(into: 12)
        var rothBalance: [Decimal] = []
        for (index, months) in years.enumerated() {
            let calcRothBalance: Decimal = months.reduce(0) { runningTotal, dept in
                let roth =  dept.depositsToRoth(index + 1)  //<- error here
                let rothIncrease = calc401k(
                    princ: princ,
                    deposits: depositsToRoth(),
                    rate401k: rate401k
                )
                return runningTotal + rothIncrease
            }
            rothBalance.append(calcRothBalance)
        }
        return rothBalance
    }

The error is: "Value of type 'Department' has no member 'depositsToRoth'"

One inherient problem is that I'm not accounting for change in principle year-to-year: the principle for year two is the balance for year one (and so on).

2      

A few issues I can see right away...

func balanceRoth(princ: Decimal, rate401k: Decimal) -> [Decimal]

The purpose of a language like Swift is so that we don't have to write everything in assembly code. As such, it should be readable to humans. Don't be afraid to give your variables, parameters, etc actual names like principal instead of abbreviating them like princ. Especially since autocomplete makes it so you usually don't have to type that much of the name in the first place.

let roth =  dept.depositsToRoth(index + 1)  //<- error here

What is the purpose of this line? You set a roth constant but then don't do anything with it in the rest of the method.

Even if you do need it, dept in this closure is an instance of a Department and that enum does not have a method called depositsToRoth(), which is why you are getting that particular error.

Also, your depositsToRoth() method takes no parameters, so that's another error.

let rothIncrease = calc401k(
    princ: princ,
    deposits: depositsToRoth(),
    rate401k: rate401k
)

Here you are passing in the result of a call to depositsToRoth() in the deposits parameter of the calc401k function. The result of depositsToRoth() is [Decimal], an array of Decimal values.

Now look at the declaration for the calc401k(princ:deposits:rate401k:) function:

func calc401k(princ: Decimal, deposits: Decimal, rate401k: Decimal) -> Decimal

What type is the deposits parameter declared as?

So take those comments into consideration and give it another whirl, see what you come up with.


To be honest, the way you keep adding more and more calculations on top of the framework I came up with for your initial question, it might be time to start considering a refactor. You've got a number of functions that are all pretty much the same except for the particular calculation at the core of the function. So you're doing a lot of the same work over and over and over. For instance, you are fetching the results of the chunked employmentHistory in every function and looping through them; there's almost certainly ways you could save on some of that work.

Of course, there is something to be said for the approach of getting it all to work as you want it to work and then refactoring. But that can sometimes be a big hassle.

2      

@roosterboy Thank you for taking time to look at my mess. I appreciate the critiques and will give it another whirl.

2      

@roosterboy

I would love to refactor at this point... but I haven't the foggiest idea on where to start or how. I feel like a toddler learning how to take my first few steps walking from the coffee table to the couch by learning how to make these basic functions actually work. Refactoring the entire code seems like the equivalent of a track coach improving the running form of his high school student athlete. Probably not an accurate analogy, but that's how it feels from this very humbling position I'm at. I'm afraid my level of conceptual understanding is not high enough yet. Each day is a battle to subvert the increasing bubbling frustration and resist the urge to give up entirely.

Here is an easier to read version of calc401k

func calc401k(principal: Decimal, deposits: Decimal, rateOfReturn: Decimal) -> Decimal {
        let rn1 = 1+((rateOfReturn/100)/12)
        let comp = pow(rn1,12)
        let totPrinc = comp * principal
        return totPrinc + ((deposits/12) * (comp-1)/((rateOfReturn/100)/12))
    }

I think my balanceRoth function is suffering because I don't fully understand the reduce(_:_:) method. From developer.apple we read:

let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
    x + y
})
// numberSum == 10

However, in func depositsToRoth() we have been using reduce(0) with the parenthesis closing immediately after the 0. The opening of the { is after the ).

I'm rewriting my balanceRoth function but I don't think I'm getting anywhere with my current level of understanding. I tried to apply the principles in the documentation and also avoid the previous problem of referencing an array in the deposits parameter when I actually want is individual elements from a loop of the array. But it is still a frustrating mess...

I'll keep working on it.

2      

I would love to refactor at this point... but I haven't the foggiest idea on where to start or how. I feel like a toddler learning how to take my first few steps walking from the coffee table to the couch by learning how to make these basic functions actually work. Refactoring the entire code seems like the equivalent of a track coach improving the running form of his high school student athlete. Probably not an accurate analogy, but that's how it feels from this very humbling position I'm at. I'm afraid my level of conceptual understanding is not high enough yet. Each day is a battle to subvert the increasing bubbling frustration and resist the urge to give up entirely.

Eh, y'know, I probably shouldn't have even mentioned it. It's far more important to understand the code and make sure it works than to clean it up. There will always be a time for that later. Don't sweat it.

However, in func depositsToRoth() we have been using reduce(0) with the parenthesis closing immediately after the 0. The opening of the { is after the ).

That's what's known as trailing closure syntax. Essentially, if a closure is the last argument to a function, you can drop the argument label and put the closure's brackets outside the parentheses. And if there are no more arguments, you can even drop the parentheses altogether.

So this:

let numberSum = numbers.reduce(0, { x, y in
    x + y
})

is the same as this:

let numberSum = numbers.reduce(0) { x, y in
    x + y
}

It can get a little more complicated than that, since a recent Swift change allows you to use trailing closure syntax with multiple parameters rather than just the final one, but that's the gist of it. Either way you want to write your function calls is perfectly fine though some might say using trailing syntax is a bit more "Swifty". You'll definitely see it more as you start to read other people's code. I recall that after Swift first came out and before I really sat down to learn it, I would look at code using trailing closures and think "WTF is going on here?!?"; it was quite confusing.

I'm rewriting my balanceRoth function but I don't think I'm getting anywhere with my current level of understanding. I tried to apply the principles in the documentation and also avoid the previous problem of referencing an array in the deposits parameter when I actually want is individual elements from a loop of the array. But it is still a frustrating mess...

Post your latest efforts and I can take another look tonight.

2      

@roosterboy Thank you for sticking with me!

I've been experimenting with loops and I'd like to know if you think the following approach would be permissible... but first, I have a question about protection against out of range parameters.

Here is an uber simplified example to highlight the question:

I've got here an array of three elements, each is the average of a year's deposits into a 401k. Only three years: the first year was an average of $100/mo deposit, second year: averaged $200/mo, and last: $300/mo.

let yearsAverageOfMonthlyRothDeposits: [Decimal] = [100,200,300]

Assuming the employee's existing 401k balance is only $1000:

var existingBalance: Decimal = 1000.0

Here is my updated formula to calculate yearly 401k balances:

func calc401k(principal: Decimal, deposits: Decimal, rateOfReturn: Decimal) -> Decimal {
    //Compound interest for principal
    // P(1 + r/n)^(nt)
    //Future value of a series
    // PMT x {[(1 + r/n)^(nt) - 1] / (r/n)}
    //Key:
    // PMT = monthly payment amount
    // r = annual interest rate
    // n = numebr of times interest is compounded per year
    // t = time in years
    // ^ = ... to the power of...

    //Start with Conpound interest for principal
    // first segment: (1 + r/n)
    // n = compounded 12 times a year
    let principalBase = 1 + ((rateOfReturn/100)/12)
    // second segment: ^(nt)
    // n = compounded 12 times a year
    // t = time is 1 year
    let principalPower = pow(principalBase,12)
    // third segment: times P
    let principalInterest = principal * principalPower

    //Now Future value of the series
    //first segment: (1 + r/n)
    let rateFrequencyCompounded = 1+((rateOfReturn/100)/12)
    //second segment:
    // ^(nt) - 1
    // n = compounded 12 times a year
    // t = time is 1 year
    let toThePower = pow(rateFrequencyCompounded,12) - 1
    //third segment:
    // divided: / (r/n)
    // n = compounded 12 times a year
    let divided = toThePower / ((rateOfReturn/100)/12)
    //fourth segment:
    // mlutiplied by monthly deposit PMT
    let futureInterest = divided * deposits
    return futureInterest + principalInterest
}

When calculating year two's balance the principal will be year one's balance. When calculating year three's balance the principal will be year two's balance. When calculating year one's balance the principal will be the existing balance variable ($1000).

The following is the code that I think will work if I can direct the principal parameter to look to the existing balance variable when the index is out of range.

for i in 0 ..< yearsAverageOfMonthlyRothDeposits.count {
    print("Year \(i + 1) 401k balance is $\(calc401k(
    principal: yearsAverageOfMonthlyRothDeposits[i - 1],  //<- naturally i - 1 is out of range
    deposits: yearsAverageOfMonthlyRothDeposits[i], 
    rateOfReturn: 10.0))")
}

Question: how do I default the principal parameter to be the exisitingBalance variable only when it is out of range?

More broadly speaking, I think this approach may work in my project but in order to use a for-in loop like above I think I will need to create a private(set) var yearsAverageOfMonthlyRothDeposits: [yearlyAverageDeposits] which collects the returns of the func depositsToRoth() ... but I don't know how to set up that relationship.

That's the direction I think I want to go, but do you see any fatal flaws in that plan?

2      

You could do something like this:

//just some simple sample data
let yearsAverageOfMonthlyRothDeposits: [Decimal] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let existingBalance: Decimal = 5

//loop through each item in yearsAverageOfMonthlyRothDeposits by index
for idx in yearsAverageOfMonthlyRothDeposits.indices {
    //our principal will either be existingBalance (for the first item)
    //  or the previous item (for items 2...n)
    let principal = idx == 0
                    ? existingBalance
                    : yearsAverageOfMonthlyRothDeposits[idx - 1]
    let balance401k = calc401k(principal: principal,
                               deposits: yearsAverageOfMonthlyRothDeposits[idx],
                               rateOfReturn: 10)
    print("Year \(idx + 1) 401k balance is $\(balance401k)")
}

More broadly speaking, I think this approach may work in my project but in order to use a for-in loop like above I think I will need to create a private(set) var yearsAverageOfMonthlyRothDeposits: [yearlyAverageDeposits] which collects the returns of the func depositsToRoth() ... but I don't know how to set up that relationship.

I must confess to some confusion over how to answer this. It's awfully hard to do without seeing everything in context, especially how your various functions are being called.

I would suggest two things:

  1. Start a new thread for your further questions, especially since this question is marked as solved. It's a little confusing to see a solved thread continue to generate questions and discussion on this level.
  2. If you have your project in a github repository, maybe share the link either in the new thread or privately so your code can be looked at with a full context.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.