encapsulation

When To Use a Category

During a phone interview I had with Web M.D. recently (it started as a lightly technical interview and then I was thrown a curve ball - see the bottom for more) I was asked to define a category and explain when I'd use one. I gave an answer, but more importantly, I gave my answer. The interviewer responded with his own answer, and from the way he explained it, that was the answer he was looking for.

In reflecting back on that interview question, I would disagree with that my interviewer said about categories. He told me that "they should primarily be used when you don't have access to the source code of a class". While I agree that categories provide a useful way to extend functionality of classes that we don't have the source code for, there is no single right answer to this question. Categories can be useful in other ways, and can be less useful in just as many ways. In disagreeing with my interviewer (which I didn't express during the interview, although thinking back on it, I definitely should have), I'll list some of my ideas here:

  1. If you need to add functionality to a class but don't have access to the source code, use a category.
  2. If you need to add data to an existing class (properties or ivars), don't use categories, and instead just subclass and make use of inheritance. I say this because categories don't support adding properties or ivars (unless making use of associated objects, which I won't get into here). 
  3. If you have a totally oversized, bloated implementation file, consider breaking up the class into specific units by using categories
  4. If you want to provide some pseudo level of encapsulation, you can add "private" methods to a category and only selectively import that category filename. However, this isn't the only way to mimic encapsulation (you can use extensions, for example), so take this one with a pinch of salt.
  5. If you have instance of a specific class littered throughout your source code and suddenly need to add functionality to that class, use a category. Your alternative would be to create a subclass, add new methods, and then replace all of your instance with the new subclass. Inefficient, to say the least. This works to your benefit in (sort-of) reverse - if you have instances of a subclass somewhere, adding methods to the parent class through a category trickles down to the subclasses.  
  6. If you absolutely, 100% do not need to create a parent-child object hierarchy, use a category

The interview question I got that really shut me down was about graphing a curve using data points representing pollen levels. The interviewer was explaining to me that there are certain things a seasoned developer with a computer science degree would know how to do that I wouldn't (I have a degree in Environmental Science, which involved high level math and science coursework). To be totally honest, I think that even if I had majored in CS, I wouldn't have remembered anything about plotting points using bezier curves and the De Casteljau algorithm. Unfortunately, I was relayed the information that although I seemed to be a solid candidate, I wasn't technically experienced enough to join the team and hit the ground running. On to the next.

INSTANCE VARIABLES & PROPERTIES

INSTANCE VARIABLES VS PROPERTIES

An instance variable is a variable that exists and holds its value for the life of the object. Instance variables (or ivars, as they're commonly referred to) are available to the entire class that they're declared in - this is in contrast to local variables, which are available only to the method they are declared in. Generally, it is bad practice to directly set the value of an ivar - instead, we abstract this process by using setter and getter methods. The concept of instance variables (and properties) has a lot to do with data encapsulation, which we'll cover towards the end of this post.

Properties are simply variables that are backed by their ivars - by declaring a property, we create an instance variable and automatically generate setter and getter methods. Additionally, properties come with a list of attributes that we can use to help further shape and define our variables - readonly, readwrite, atomic, nonatomic, strong and copy.

A readonly property is when the backing ivars setter method is never synthesized.

A readwrite property generates both getters and setters.

An atomic property guarantees that a fully initialized object is always returned - the object is locked when being set or get so that it is not being simultaneously accessed from another thread. You will never see a "partial write" for an atomic property. Atomicity doesn't imply thread-safety! Consider an example where you have a first and last name, both atomic, both being accessed and set from two threads (one thread sets the initial first and last names, the other changes them). While you can always guarantee that you will be returned a full string for the first name and a full string for the last name (no partial writes), you cannot guarantee which thread is returning the value. You may get the original first name (from the first thread) and the changed last name (from the second thread), which is not the combination of values you perhaps expected.

A nonatomic property makes no guarantees regarding object initialization.

A strong property creates an owning relationship between the property and the assigned value. This is the default for properties. If a Car object has a @property (strong) Person *driver, and in our implementation file we write Car * Honda = [Car new]; and we have Person *John = [Person new]; and Honda.driver = John, then Honda has strong ownership of John. As long as Honda needs its driver, John will exist. 

A weak property creates a non-owning relationship between the property and the assigned value. This can be used to prevent retain cycles. In our previous example, if Person has a property called @property (strong) Car *car, and we have John and say John.car = Honda, we have a problem. Honda has strong ownership of its driver, John, but John also has strong ownership of his car, Honda. These objects, because of the strong relationship, will ALWAYS be owned by another object. If they’re no longer needed, they still can’t be destroyed - this is a retain cycle. A retain cycle is when two objects have a strong relationship to one another and thus can’t be destroyed, and no other objects hold a reference to either of them. The way around this is to use the weak property attribute - if John has weak ownership of his Honda, then we can avoid this retain cycle. If Honda is deallocated, because John has a weak relationship to it, that won’t be a problem - however, John.car will, by default, be set to nil. 

Keep in mind that if we want to use Key Value Observing (KVO), we must user properties in our classes. This is a means of notifying a current class when a property value has been accessed in a different class. It provides a means of communicating between different classes. Additionally, properties don’t HAVE to be global - if we declare them as class extensions (declared in our implementation file) as (readwrite), we can use them as we like in the class file. In the interface file, we can declare those same properties as (readonly) - other classes will not be able to write values to that property, essentially encapsulating that data. 

Data encapsulation encompasses the idea that data should be hidden and confined to a single area of software as much as possible, unless it is necessary that it be available to other classes. There are many, many ways to go about doing this, and it's up to the developer to decide how they want to go about it. You can hide ivars and properties in a class extension, making them available only to that class. You can create a category, use public variables, and import that category into your class for use. 

*As a side note, I almost always use properties instead of explicitly declaring ivars.

If data needs to be publicly available, it is bad practice to make it possible for other classes to change that variables value - in this case, you can declare a readonly property in a class interface file, and redeclare it as readwrite in the implementation file. This makes it so that you can internally change the value of that variable, but no other classes can write new values to it. To make properties "private" (although there is no such thing as a truly private variable in objective-c due to its dynamic runtime) you can simply put them in a class extension - this is my typical encapsulation workflow. dditionally, if you will be using publicly available variables from one class, but you are only using them internally, you can write your import statement for that class ONLY in your implementation file.

Between the @interface and @end tags, we have declared a private property. This is one way of using an extension to house private variables.   After the @implementation tag, we have declared both a private and public ivar between the curly braces. We can still achieve data encapsulation without using extensions, as shown here. 

Between the @interface and @end tags, we have declared a private property. This is one way of using an extension to house private variables. 

After the @implementation tag, we have declared both a private and public ivar between the curly braces. We can still achieve data encapsulation without using extensions, as shown here. 

To recap - 

  1. Try and declare ivars or properties in categories as much as possible - this limits their exposure to the class they are declared in.
  2. If you need to expose a variable to other classes, try and make them readonly properties in your interface file and make them readwrite in your implementation file.
  3. All property variable are backed by ivars - they simply generate setters and getters automatically and come with several attributes you can utilize that deal with atomicity, encapsulation (readonly) and memory management.
  4. NOTE - If you don't want to put your variables in an extension, you can just put them in curly braces right after your @implementation "class name" in your .m file. This also encapsulates your data - I prefer using extensions because I think it makes my code more readable. 

Last but not least, if you want other classes to be able to change the values of a variable you have, you can keep the variable private and still accomplish this - create a public method, declared in your interface file, that internally changes the value of the private variable (see below). This is often used for further encapsulation, as it is bad practice in a large code base to allow other classes to directly change the value of an object. Once again, the way you choose to encapsulate your data depends entirely on your preferences and the data you have at hand - different pieces of software will always have different encapsulation requirements. 

On the left, we have the interface (.h) class file, and in it, we have a public readonly property and a public method. On the right, we have the implementation (.m) file with an extension declared. In the extension, we have redeclared our readonly property to be readwrite - other classes can now READ the variable value directly (it is publicly declared on the left) but cannot directly alter the value of it (since it's publicly readonly). In order to change the value, other classes must go through our publicly declared method, the implementation of which changes the property value.

On the left, we have the interface (.h) class file, and in it, we have a public readonly property and a public method. On the right, we have the implementation (.m) file with an extension declared. In the extension, we have redeclared our readonly property to be readwrite - other classes can now READ the variable value directly (it is publicly declared on the left) but cannot directly alter the value of it (since it's publicly readonly). In order to change the value, other classes must go through our publicly declared method, the implementation of which changes the property value.