When designing your data you need to understand the concept of ownership. Data owns downwards. Ownership can never go back up your data hierarchy. If A has a pointer to B, and B to C, then C owns A, you have a cyclic reference graph, which results in a memory leak due to A referencing C indirectly and C referencing A. Release A and it doesn't get deleted because C still has a reference, and it won't get deleted unless A does - a catch 22.
To avoid scenarios like this, you use strong pointers to point "down" your data, and use weak pointers for any back references (such as parent pointers for example).
If a property is atomic, it generates a setter that allows it to be set from multiple threads. You cannot have race conditions where one thread changes a property at the same time as another. Nonatomic properties don't have that thread locking system.
Finally, retain properties increase the reference count of an object when you assign them to it by calling [myObject retain] on the object. Copy calls [myObject copy] so the property does not refer to the original, but a copy and assign is just a straight assignment with no reference count adjustment.