A set is most often used when you need to see if one object is part of a group.
For example, let's say you had an array with 100,000 random numbers. If you wanted to figure out if the array contained a certain number, you would have to walk through the array, checking each element--this could potentially take 100,000 operations!
In a set, the elements are kept in a special data structure that allows fast lookup. Determining if a certain number is present in a group 100,000 will be much, much faster if you use a set than if you used an array.
Since each element must be unique, a set is basically a dictionary of keys with no associated values. Likewise, a dictionary is a set where each element can have a value associated with it.
An NSCountedSet (also known in the computer science world as a "bag" or multiset) is a mix between a set and a dictionary. Each element has a count associated with it that keeps track of how many times that element occurs in the collection. For example, the values "a", "b", "c", "b", "c", "c" would produce a counted set where "a" => 1, "b" => 2, and "c" => 3. Lookups in a counted set are just as fast as with a set or dictionary.
tl;dr: use an NSSet/NSCountedSet/NSDictionary when you need to perform lots of lookups/membership tests and they need to be fast. Use an NSArray for practically everything else. And google "computational complexity theory."