Value Types vs Reference Types
So, watching the 2015 WWDC Videos turned me on to value types as opposed to reference types. Three weeks ago, I understood that such things existed, but didnāt have any clue how they worked. This comes from a deep distrust of pointers when I was first coding in the mid-90s (all of my friends opted for C++, but I didnāt want to have to deal with pointers, so I picked C -- Iām going to guess that not using Windows also pushed me in that direction).
So, mostly I was scared of pointers. Which is stupid because they are all over the place, pretty much whatever language you are using. I never got that a pointer is basically a reference. It looks like a variable!
NSNumber *number = @2;
So, when I use number, Iām passing around the number two, right? I mean, that seems simple enough. But, no, thatās not really whatās happening. Really, whatās going on is that Iām passing around a reference to the location of that NSNumber object. When the computer needs it again, it doesnāt know what it is immediately and has to look it up, since it only knows whereĀ it is, not what it is.Ā This is a reference type, and itās helpful because it means that you donāt need to Ā save the same thing in multiple places just because itās referenced there.
Gosh, that sounds great, right? Imagine you and I are in the subway and need to know how to get somewhere. We donāt need to remember how to get there. We just need to remember where to look. Neither of us needs our own map, because there are maps all over the subway to tell us where to go. Basically, we just need to run through the process of finding a map and looking where to go on that map.
The map idea is interesting, because it actually presents a compelling case for Reference Types. What happens if the map changes because a transit station is closed? If we rely on our own maps, weāre going to end up with bad information and a difficult commute. In this case it makes sense to rely on the central information because it will be as up-to-date as possible.
But whatās the alternative? Instead of relying on the transit authority, you and I carry around our own maps in our pocket.
When we need to know which way to go, we pull them out and look ourselves. Thereās no need to remember where the map is because itās in our pocket. It might have outdated information, but itās faster. And itās always going to be there, unless we throw it away. What happens when the transit authority decides it can use its space more efficiently with an advertisement where the map currently is? You and I will know to fall back on our pocket map, but computers are like a two-year-old in comparison. The computer will try to load the data from the reference you gave it and fall apart because it doesnāt look like what it expected. It will throw a tantrum and refuse to do anything more.
Reference types in Objective-C also lead to some other issues that are not immediately obvious. Take this example from something that I was working on today:
if (array1 == array2) { ... }
This was never evaluating true, and it was causing trouble down the line, because it was a check to find some incorrect data stored in a database that needed to be changed. Hereās what the arrays looked like in shorthand:
array1: [2,2,2,2,2,2] array2: [2,2,2,2,2,2]
Huh. The contents of the arrays are exactly the same. But the arrays are never being treated as equal. Well, this is a classic example of Reference Types letting you down. In Objective-C, the equality operator (==) is more of an identity operator which means that the two references point to the same memory address. In other words, two Reference Type objects are equal by default if they reference the exact same object.Ā In my example above, the two arrays will neverĀ be considered the same unless their contents are evaluated. The question I am asking above can be translatedĀ āAre these two objects the same object?ā
In the case of the transit map, if they come from different places, they are never going to be the same map. Is the map on this wall the same one as the map on that wall?
Of course not,Ā because they come ultimately from different places. So we have to use a different method of checking equality. Something that asks the proper questionĀ āDo these two objects contain the same things?ā Thankfully, Apple provides this for NSArray:
- (BOOL)isEqualToArray:(NSArray<ObjectType>*nonnull)otherArray
Return Value YES if the contents of otherArray are equal to the contents of the receiving array, otherwise NO. Discussion Two arrays have equal contents if they each hold the same number of objects and objects at a given index in each array satisfy the isEqual: test.
So hereās what the array check looks like, properly, in Objective-C:
if ([array1 isEqualToArray:array2]) { ... }
Swift fixes this by making arrays into Value Types. When you assign a value type, it makes a copy rather than assigning a reference. Itās the equivalent of taking another map at the transit station. Whatās more, it doesnāt really make sense to ask the question of a Value TypeĀ āAre these the same object?ā because Value Types are copied on assignment rather than referenced. Their very nature precludes the possibility of the computer misunderstanding a reference and throwing a temper tantrum.
Whatās the downside? First of all, some things legitimately canāt be stored as Value Types; as the name implies, they are useful for values -- numbers, colors, characters, etc. Further, Value Types are copied on assignment, meaning that they are ultimately going to take more memory (as for speed, I donāt know the answer well enough to know if they tend to be faster or slower).
So, why use Value Types at all? Ask yourself that question the next time you see EXC_BAD_ACCESS. Greater type safety and fewer crashes on code that is running on your usersā devices is probably the best reason. Then thereās the fact above that equality starts to mean something more reasonable when you are reading your code three months down the line...
Iām ready to buy in.













