Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Why is this happening? (Functions and DRY)

I need some help understanding functions implementation. This question is regarding the first Swift's TechDegree Project, the SoccerCoordinator.

I have 3 teams, each team stored in its own variable dictionary. I want to iterate each one, and update some values using updateValue.

Now, this is the way I did it:

for i in 0..<dragons.count {
    dragons[i].updateValue("March 17, 1pm", forKey: "practice")
    dragons[i].updateValue("Dragons", forKey: "team")
}

for i in 0..<sharks.count {
    sharks[i].updateValue("March 17, 3pm", forKey: "practice")
    sharks[i].updateValue("Sharks", forKey: "team")
}

for i in 0..<raptors.count {
    raptors[i].updateValue("March 18, 1pm", forKey: "practice")
    raptors[i].updateValue("Raptors", forKey: "team")
}

Not DRY, I know... So i want to convert it into a function in order to be more DRY... I then try to do this:

func updatePracticeAndTeam(team: [[String:String]], practiceDay: String, teamName: String) {
    for i in 0..<team.count {
        team[i].updateValue("\(practiceDay)", forKey: "practice")
        team[i].updateValue("\(teamName)", forKey: "team")
    }
}

And the output is that I should mark team as a var to make it mutable (If I do that, it kinda "works" but instead of updating the key with the value, it outputs nil.

And when I try this:

func updatePracticeAndTeam(team: [[String:String]], practiceDay: String, teamName: String) {
    for player in team {
       player.updateValue("\(practiceDay)", forKey: "practice")
       player.updateValue("\(teamName)", forKey: "team")
    }
}

And it doesn't work too :( The output is "error: cannot use mutating member on immutable value: 'player' is a 'let' constant"

What am I possibly doing wrong? Thanks in advance!

2 Answers

Hi Jonathan,

First: the error you get is because player is a constant, so if you add var in front of it the error will disappear. But the trick is that the function still wont do what is needed. The reason is you are dealing array of dictionaries which is a value type.. this means when you pass team to your function, you are actually copying it.. so any change you make to that copy wont affect the original. I suggest to convert it to a class so you can use it as a reference type.

Another tricky way is what I introduced below, it is a kind of trying to handle the array/dictionary which is a value type in a refernce type way. first change is to mark team as inout variable, so this allows the function to modify the content being passed to it. second, change the content of team itself without using a player variable, so change happens to team array itself third, when you call this function you need to add & before the team array you are passing, this will inform swift to pass the memory location of that array instead of the array copy(kind of similar to working with classes)

updatePracticeAndTeam(&myteamarray, practiceDay: "day", teamName: "dragons")

The solution is a bit tricky as explained above:

func updatePracticeAndTeam(inout team: [[String:String]], practiceDay: String, teamName: String) -> [[String:String]]{
    for i in 0..<team.count {
        team[i].updateValue ("\(practiceDay)", forKey: "practice")
        team[i].updateValue("\(teamName)", forKey: "team")
    }
return team
}

I know it could be confusing, please let me know if you need more clarification.

Thanks, Safwat

Another way that could be easier to implement: you change the function to make it return a array of dictionaries as below. Then create a new array inside the function and fill it with modified data, then return it

func updatePracticeAndTeam2(team: [[String:String]], practiceDay: String, teamName: String) -> [[String:String]]{
    var newteam = [[String:String]]()
    for var player in team {
        player.updateValue("\(practiceDay)", forKey: "practice")
        player.updateValue("\(teamName)", forKey: "team")
        newteam.append(player)
    }
    return newteam
}