Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

mentaluproar

macrumors 68000
Original poster
May 25, 2010
1,774
224
Ohio, USA
I've read the apple Everyone Can Code stuff, and am going through Programming in Swift on Raywenderlich.com, but I'm really getting tripped up by closures. I wish I could just skip them, work on my apps, and then gradually make it cleaner by incorporating closures, but so many things depend on closures to work I have to understand this NOW.

I get that they are little baby functions. I get that they can bring out a value from a context that has otherwise ended. But that's it. I can't seem to pull them back apart. Its so clean and nice as they go through how it works, but then we get to trailing closures and using them in collections and I'm just lost.

Is there another place I could find a better explanation of closures? The way it's being explained isn't making sense to me.
 
This is a good example of where I'm screwing up. In this example:

names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 < s2 })

I would expect an array of Bools. Why am I not getting that?
[doublepost=1553993847][/doublepost]Another example:

let names = ["Sean", "Harry", "Mason", "Ada", "Alamo"]

let allNames = names.reduce(""){ result, name in

return result + " " + name

}

What is result? Where was that variable declared? I don't understand where its coming from.
 
sort() sorts an array in place. sorted() return a new array that is a sorted version of the input array. The closure version of these methods takes a closure that compares two members of the array and returns a Bool indicating if the first item is ordered before the second item. Obviously the sort algorithm, quick sort, binary sort or whatever it is, is more complicated than just comparing all the items in the array. But also it should be obvious that the sort algorithm depends, in part, on comparing two items at a time. So the sort algorithm runs and it asks the closure to compare two items. It places the items at the correct position in the array and continues to call the closure until all the items are in their correct positions.

Reduce is a little complicated. You should understand sort, map, filter before you tackle reduce.
 
  • Like
Reactions: MisterSavage
I get that sort is just a bubble sort. I get that for a bubble sort to work, it only sorts two elements at a time, starting the loop over each time something fails the < test.

I'm not seeing the closure doing that. I can't read the steps involved in a function in the closure.
 
There's no reason to think that sort() uses a bubble sort. It might but it probably doesn't. It doesn't matter what the algorithm is. The point is that all the code for the sort algorithm is inside the standard library. The only part it needs is the comparison code. And that's provided by the closure. This allows sorting of any kind of object that can be put into an array and that can be compared.

In olden times the comparison was provided by a comparison function. The function received two objects and returned the comparison result. In objective-c it wasn't a boolean that was returned but a three way choice of less than, equal, greater than. The closure is like the comparison function, although the parameters and the result are slightly different.

The even simpler version of sorted() uses the < or > operator to do the sorting. That requires the objects in the array to support these operators. No closure is required in this case because the library knows how to apply those operators to the Elements in the array. And of course the simplest version just does an ascending sort and takes no parameters.

Here's some code I wrote in a playground. You only need the closure when sorting for more complicated cases and it works a lot like a comparison function. Maybe it's the terseness of closures that's confusing. Also, understand that the closures for map, filter, reduce, sort and other uses all take different parameters and return different types that have different meanings. So for sorting returning a Bool is the comparison result not the type of value that's being accumulated into the sorted array.

Code:
let names = ["Sean", "Harry", "Mason", "Ada", "Alamo"]
let namesSorted = names.sorted()
let namesSortedOneWay = names.sorted(by: <)
let namesSortedOtherWay = names.sorted(by: >)

struct Person {
    let name: String
    let age: Int
}

let sean = Person(name: "sean", age: 10)
let harry = Person(name: "harry", age: 11)
let mason = Person(name: "mason", age: 12)
let persons = [sean, harry, mason]

//let personsSorted = persons.sorted()             // doesn't compile
//let personsSortedOneWay = persons.sorted(by: <)  // doesn't compile
let personsSortedByName = persons.sorted(by: { person1, person2 in return person1.name < person2.name })
let personsSortedByAge = persons.sorted(by: { person1, person2 in return person1.age < person2.age })
print("\(personsSortedByName)")
print("\(personsSortedByAge)")
let personsSortedByName1 = persons.sorted(by: { $0.name < $1.name })
let personsSortedByAge1 = persons.sorted(by: { $0.age < $1.age })
print("\(personsSortedByName1)")
print("\(personsSortedByAge1)")
 
Last edited:
  • Like
Reactions: grandM
okay, so the Bool isn't actually being returned to the array. It's just looping through until the bool tells it to stop. Since it's not actually returning a bool for array values, it's actually acting on the array. It's really difficult to read, but I kind of get it.

Man, closures looks really useful but I'm just not doing that well.
 
OK you're on your way. The Bool is the comparison result ($0 < $1), not a stop flag.

I think if you look at map and filter you'll understand it more. Really closures are just a terse way of writing an anonymous function. You can skip reduce for now ;-)
 
I think I'll get better with them as I use them more. Is there a cheatsheet I can pin up next to my monitor to use until I get it? I found one on GitHub but it's a bit complex.
 
I don't know about a cheat sheet. These kinds of closures for the standard library methods are relatively simple. If you use third party libraries like AlamoFire or write your own it gets more complicated.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.