In this (long) series of posts, I'll be posting groups of questions on iOS concepts as they come to me. I have no direction in the questions I'm choosing to answer, I'm simply going to go through notes of mine, find random questions, and answer them. If questions come up in this series that need deserve dedicated posts, I'll link to another blog post that discusses the topic more fully (think something like multithreading with GCD).
- Deep copy v. Shallow copy v. Assignment
A shallow copy simply copies references to a place in memory. If object B is a shallow copy of object A, it simply copies object A's references (pointers) to objects in memory. Object B then refers to that same place in memory. Making changes to the data contained in one of the objects will impact the very same data being used by the other.
In contrast, a deep copy makes copies of the actual data, storing it elsewhere in memory. Changing the data contained in one object will have no impact on the other.
Assigning one object to equal another creates a pointer to a group of pointers, which point to memory. That is, if you have dictionary *A, and dictionary *B = A, then B contains a pointer to A's pointers, which point to the objects in memory. Although it will behave the same as a shallow copy, in a shallow copy, B would actually contain each pointer that A contains, still pointing to the same objects in memory. In either case, changing the values of one will change the other.
- Heaps and Stacks in iOS - how are they used?
Almost all objects in iOS development are stored on the heap - they can be accessed globally and must be manually released and deallocated (pre-ARC). Stack objects disappear when a function returns and don't need to be manually managed. Imagine if stacks were widely used in iOS - what would happen if you needed to keep one around after the function returned? You could retain it, but after the function ended, that retain command would be pointing to a non-existent object - a dangling pointer. As a result, almost all objects are placed on the heap - the exception is blocks.
Blocks are actually stored on the stack - that's why variables created within blocks aren't accessible outside of the block. They no longer exist when the block (which is treated like a function) ends; to continue to use them outside of the scope of the block, you must use a __block variable before entering the block. You can also create a copy of the block variable you wish to use, which actually places that copy on the heap.
- What are block variables used for?
Using block variables (prefaced with a double underscore during declaration) is a way to access information created within a block outside of the block itself (remember that objects created within a block are stored on the stack, and as such disappear when the block exits). You could technically have an array created within a block, have an array property, and set the array property equal to the block array. However, this array is now accessible from everywhere else in the program since it's a global property - for the sake of data encapsulation, block variables are a better choice.
- What is a message in Objective-C? A Method? A selector?
Messages and Methods are conceptually different in Objective-C but not so different practically.
Objective-C runtime keeps a list of methods and functions it is aware of. When compiled, method names are turned into selectors (representations of the method name in memory). A function, objc_msgSend, is also called - it does a dynamic lookup, where it goes to the list of functions and finds the one we need (which is represented as a selector).
This dynamic lookup allows us to do some interesting stuff - we can change the list at will. We can move values so that selectors point to different code than what was written. Additionally, the runtime asks objects if it recognizes methods before it actually sends a message. An object can then choose if it even wants to respond to that message.
In short, when calling a method, there is little ambiguity - we know who is performing the action. The object did something.
However, when we send a message, that ambiguity does exist. Something was done by the object. The emphasis is no longer on the object, but rather that “something” was done - when we send a message, we can’t be entirely sure what will respond, since dynamic lookup allows us to change certain things about our list of functions. The focus is more on the message itself.