Types

The type system in Objective-C is a little bit more disparate than Swift. This is because the structures and enumerations in Objective-C come from C. Only classes and categories come from the Objective-C extension.

In Swift, structures are very similar to classes, but in Objective-C, they are much more different. Structures in Objective-C are essentially just a way of giving a name to a collection of individual types. They cannot contain methods. Even more restrictive than that, structures can't contain Objective-C types. This leaves us with only basic possibilities:

Structures in Objective-C start with the keyword typedef, which is short for type definition. This is then followed by the struct keyword and the different components of the structure contained within curly brackets. Finally, after the curly brackets is the name of the structure.

Advanced C programmers will do a lot more with structures. There are ways to simulate some features of inheritance with structures and to do other more advanced things, but that is beyond the scope of this book and not very relevant in most modern programming projects. There are some types in Apple's APIs that are structures like CGRect so you should know how to interact with them, but you most likely won't have to deal with custom structure definitions when looking at Objective-C resources.

Enumerations are also much more restrictive in Objective-C. They are really just a simple mechanism to represent a finite list of related possible values. This allows us to still represent possible primary colors:

Just like with structures, Objective-C enumerations start with the keyword typedef followed by enum with the name at the end of the definition. Each case is contained within the curly brackets and separated by a comma.

Notice that every case of the enumeration starts with the name of the enumeration. This is a very common convention, to make it easy for code completion and to show all possible values of an enumeration. This is because in Objective-C, you cannot specify a specific enumeration value through the name of the enumeration itself. Instead, every case is its own keyword. This is why when we are assigning our color variable to blue; we use the case name by itself.

Enumerations in Objective-C cannot have methods, associated values, or represent any other values except for integers. In fact, in Objective-C enumerations, every case has a numeric value. If you don't specify any, they start at 0 and go up by 1 for each case. If you want, you can manually specify a value for one or more of the cases:

Each case after a manually specified case will continue to increase by one. This means that in the preceding code PrimaryColorRed is still 0 but PrimaryColorBlue is 11.

Unlike Objective-C structures and enumerations, classes are very similar to their Swift counterparts. Objective-C classes can contain methods and properties, use inheritance, and get initialized. However, they look pretty different. Most notably, a class in Objective-C is split into two parts: its interface and its implementation. The interface is intended to be the public interface to the class, while the implementation includes the implementation of that interface in addition to any other private methods.

Let's start by looking again at our contact class from Chapter 3, One Piece at a Time – Types, Scopes, and Projects and what it looks like in Objective-C:

class Contact {
    var firstName: String = "First"
    var lastName: String = "Last"
}
@interface Contact : NSObject {
    NSString *firstName;
    NSString *lastName;
}
@end

@implementation Contact
@end

Already Objective-C is taking a lot more lines of code. First, we have the interface declaration. This begins with the @interface keyword and ends with the @end keyword. Within the square brackets is a list of attributes. These are essentially the same as the attributes of a structure, except that you can include Objective-C objects in the attributes. These attributes are not commonly written like this because using the properties will create these automatically, as we will see later.

You will also notice that our class is inheriting from a class called NSObject, as indicated by : NSObject. This is because every class in Objective-C must inherit from NSObject, which makes NSObject the most basic form of class. However, don't let the term "basic" fool you; NSObject provides a lot of functionality. We won't really get into that here, but you should at least be aware of it.

The other part of the class is the implementation. It starts with the @implementation keyword followed by the name of the class we are implementing and then ends again with the @end keyword. Here, we have not actually added any extra functionality to our contact class. However, you may notice that our class is missing something that the Swift version has.

Objective-C does not allow specifying default values for any attributes or properties. This means that we have to implement an initializer that sets the default values:

In Objective-C, initializers are the exact same as a method, except that by convention they start with the name init. This is actually just a convention but it is important, as it will cause problems down the line with memory management and interacting with the code from Swift.

The minus sign at the beginning indicates that this is a method. Next, the return type is specified within parentheses, which is then followed by the name of the method: in this case init. The body of the method is contained in curly brackets just like a function.

The return type for all initializers is going to be id by convention. This allows us to easily override initializers of subclasses.

Virtually all initializers will follow this same pattern. Just like in Swift, self references the instance that this method is being called on. The first line assigns the self reference to the result by calling the superclass's initializer with [super init]. We then allow for the possibility that the initializer fails and returns nil by testing it for nil in the if (self) statement. The if statement will fail if self is nil. If it is not nil, we assign the default values. Finally, we return self, so that calling code can maintain a reference to the newly initialized object. However, this is just a convention and Objective-C does not have any protection around properly initializing properties.

The Objective-C version of the contact class still isn't exactly like the Swift version because the firstName and lastName attributes are not accessible from outside the class. To make them accessible we need to define them as public properties and we can drop them from being explicit attributes:

Note that the properties are defined outside of the curly brackets but still within the @interface. In fact, you can leave off the curly brackets altogether if you have nothing to define in it. Properties automatically generate attributes by the same name except with an underscore at the beginning:

Alternatively, you can just set the values using self:

There are nuances to each approach but for just general reading purposes, it doesn't matter which one is used.

Also, just as you can define weak references in Swift, you can do so in Objective-C:

If you want, you can replace weak with strong, but just like Swift, all properties are strong by default. Weak references in Objective-C will automatically be set to nil if the referenced object gets deallocated. You can also use the unsafe_unretained keyword, which is equivalent to unowned in Swift. However, this is rarely used as the only difference between the two in Objective-C is that unsafe_unretained does not reset the value to nil; instead, it will reference an invalid object if the object gets deallocated causing confusing crashes if used.

In addition to weak or strong, you can also specify that a property is readonly or readwrite:

Each property attribute should be written inside the parentheses separated by a comma. As the readonly name implies, this makes it so that the property can be read but not written to. Every property is read-write by default, so normally it is not necessary to include it.

Note that you may also see the keyword nonatomic in the parentheses. This is a more advanced topic that is beyond the scope of this book.

Categories in Objective-C are just like Swift extensions. They allow you to add new methods to existing classes. They look very similar to plain classes:

We know that this is a category instead of a normal class because we added a name within parentheses after the class name. Every category on a class must have a unique name. In this case, we are calling it Helpers and we are adding a method to return the contact's full name.

Here, for the first time, we are declaring a method inside the interface. This is also possible with classes. A method definition looks exactly like an implementation except that it ends in a semicolon instead of the code inside the curly brackets. This will allow us to call the method from outside the current file, as we will see in more detail in the upcoming projects section.

Categories can also add properties, but you will have to define your own getter and setter methods because just like Swift extensions can't add stored properties, Objective-C categories can't add attributes:

These types of properties are very similar to calculated properties. If you need to allow reading from a property, you must implement a method with the exact same name that takes no parameters and returns the same type. If you want to be able to write to the property you will have to implement a method that starts with set, followed by the same property name with a capital first letter, that takes the property type as a parameter and returns nothing. This allows outside classes to interact with the property as if it were an attribute, when in fact it is just another set of methods. Again, this is possible within a class or a category.

Like Swift, Objective-C has the idea of protocols. Their definition looks similar to this:

Here, we are using the @protocol keyword instead of @interface and it still ends with the @end keyword. We can define any properties or methods that we want. We can then say that a class implements the protocol similar to this:

The list of protocols that a class implements should be listed within angled brackets after the class it inherits from separated by commas. In this case we are only implementing a single protocol so we don't need any commas. This code also declares a contents property, so that we can implement the protocol as shown:

Note that we don't do anything special in the implementation to implement a protocol; we just need to make sure the proper methods and computed properties are implemented.

The other thing you should be aware of is that protocols in Objective-C are not used in the same way as classes. You can't just define a variable to be a protocol; instead, you must give it a type and require that it implement the protocol. Most commonly, this is done with the id type:

Any variable declaration can require that it not only inherits from a specific type, but also implements certain protocols.

Lastly, blocks are the Objective-C alternative to closures in Swift. They are actually a late addition to Objective-C so their syntax is somewhat complex:

Let's break this down. We start like any other variable with the variable's name and type before the equals sign. The name starts with a carrot symbol (^) inside the first set of parentheses. In this case, we are calling it doubleClosure. The actual type of the closure surrounds that. The type it starts with is the type the closure returns, which in this case is an int. The second set of parentheses lists the types of the parameters the closure accepts. In total, this means that we are defining a closure called doubleClosure that accepts int and returns int.

Then, we move on to the business of implementing the closure. All closure implementations start with a carrot symbol followed by any arguments in parentheses and curly brackets with the actual implementation. Once a closure is defined, it can be called similar to any other function. However, you should always be aware that it is possible for a closure to be nil, in which calling it will cause the program to crash.

It is also possible to define a function or method that accepts a closure as a parameter. First, a function:

Note that the type id signifies any Objective-C object and even though it doesn't have an asterisk, it is a reference type. The usage above looks exactly like a standalone block usage. However, the syntax looks somewhat different in a method:

This is because a method's parameter name is separated by parentheses. This causes the name of the parameter to be moved from being with the carrot to after the parentheses. In the end, we can say that the nuances of the syntax aren't too important when reading Objective-C code and translating to Swift, as long as you recognize that a carrot symbol indicates a block. Many Objective-C programmers look up the syntax of a block on a regular basis.

All of the same memory concerns exist in Objective-C with blocks. By default, all arguments are captured strongly and the syntax to capture them weakly is much more convoluted. Instead of including the weak captures in the block itself, you must create weak variables outside of the block and use them:

Here we use the keyword __weak (that has two underscores) to indicate that the weakBall variable should only have a weak reference to ball. We can then safely reference the weakBall variable within the block and not create a circular reference.