Objective-C Runtime in Practice

Class and Object Operation Functions Class Operation Functions The methods that provides for operating on classes are mostly targeted at the various fields of the struct. Below we introduce these functions one by one, and conclude with a practical example demonstrating their usage. Class Name (name) The main functions for class name operations: For : if the passed-in is , an empty string is returned. Superclass (superclass) and Metaclass (meta-class) The main functions for superclass and metaclass operations: : returns when is or is a root class. You can usually use NSObject's method to achieve the same result. : returns if is a metaclass; returns if not, or if is . Instance Variable Size (instancesize) Member Variables (ivars) and Properties In , all member variable and property information is stored in the linked list . is an array where each element is a pointer to (variable info). The runtime provides a rich set of functions for operating on this field, which can be broadly categorized as: 1. Member variable operation functions, mainly including: : returns a pointer (Ivar) to the struct containing info about the member variable named . : no information on class variables in Objective-C has been found; it is generally accepted that Objective-C does not support class variables. Note: the returned list does not include member variables and properties inherited from parent classes. Objective-C does not support adding instance variables to existing classes — neither system-provided classes nor custom classes support it dynamically. However, if you want to add a member variable to a class created at runtime, you can use . Note that this can only be called between and , and the class cannot be a metaclass. The minimum byte alignment for a member variable is , which depends on the ivar's type and the machine's architecture. If the variable type is a pointer, pass . : returns an array of pointers to member variable info, where each element is a pointer to the struct. This array does not include variables declared in parent classes. The pointer returns the size of the array. You must use to release this array. 2. Property operation functions, mainly including: These methods also operate on , but only on those that are properties. We'll encounter these functions again when we cover properties later. 3. On Mac OS X, you can use a garbage collector. The runtime provides several functions to determine whether an object's memory regions can be scanned by the garbage collector for strong/weak references: Normally, you don't need to call these methods directly; a sensible layout is generated when is called. These functions won't be detailed further here. Methods (methodLists) The main method operation functions: will override the parent class's method implementation but will not replace an existing implementation in the same class — if the class already contains an implementation with the same name, the function returns . To modify an existing implementation, use . An Objective-C method is a simple C function that takes at least two parameters — and — so our implementation function (the function pointed to by the parameter) must also take at least two parameters: Unlike member variables, you can dynamically add methods to a class regardless of whether it already exists. Also, the parameter is a character array describing the types of the arguments passed to the method. This involves type encoding, which we'll cover later. and : unlike , both of these functions search the parent class's implementations as well. : returns an array of all instance methods. To get class methods, use (a class's instance methods are defined in the metaclass). The list does not include methods implemented in parent classes. The parameter returns the number of methods. After obtaining the list, call to release it. : its behavior splits into two cases — if the class does not have a method named , it acts like and adds the method; if the method already exists, it acts like and replaces the original implementation. : this function is called when a message is sent to a class instance, and returns a pointer to the method implementation function. It is faster than . The returned pointer may point to a runtime-internal function rather than the actual method implementation — for example, if the class instance cannot respond to the , the returned pointer will be part of the runtime's message-forwarding mechanism. : we typically use NSObject's or methods to achieve the same purpose. Protocols (objcprotocollist) Protocol-related operations include: can be replaced by NSObject's method. returns an array; call manually after use. Version and Other Functions Version-related operations, plus two functions the runtime provides for 's toll-free bridging: Example Let's look at the code directly: Output: Dynamically Creating Classes and Objects Dynamically Creating Classes Dynamically creating a class involves the following functions: : to create a root class, specify as . is usually 0; it represents the number of bytes to allocate at the end of the class and metaclass objects for indexed . To create a new class, call . Then use functions like and to add methods, instance variables, and properties to the new class. Once done, call to register the class so it can be used in the program. Instance methods and instance variables should be added to the class itself, while class methods should be added to the class's metaclass. destroys a class. Note: if instances of the class or its subclasses still exist in the running program, do not call this on the class. We've already seen these functions when discussing metaclasses. Here's another example to illustrate their usage: Program output: Dynamically Creating Objects The functions for dynamically creating objects are: : when creating an instance, memory is allocated for the class in the default memory area. The parameter specifies the number of extra bytes to allocate. These extra bytes can be used for instance variables beyond those defined in the class definition. This function cannot be used in an ARC environment. Calling is similar to . However, when using you need to know exactly what you're doing. The following example uses to test the function's actual behavior: Output: You can see that using returns an instance rather than the default placeholder class from the class cluster. : creates a class instance at the specified location (). : destroys a class instance but does not free or remove any associated references. Instance Operation Functions Instance operation functions primarily target a series of operations on the instance objects we create. We can use these functions to obtain information from instance objects, such as the values of instance variables. These functions fall into three subcategories: 1. Functions that operate on the entire object: Consider this scenario: we have class A and class B, where B is a subclass of A. B extends A by adding some extra properties. We've created an instance of A and want to convert it to a B instance at runtime so we can store data in B's properties. We can't convert directly because a B instance is larger than an A instance — there isn't enough space. The functions above can handle this: 2. Functions that operate on object instance variables: If the of an instance variable is already known, calling is faster than ; similarly, is faster than . 3. Functions that operate on an object's class: Getting Class Definitions The Objective-C dynamic runtime automatically registers all classes defined in your code. You can also create class definitions at runtime and register them using . The runtime provides a series of functions to get class definition information, mainly: : gets the list of registered class definitions. We cannot assume that class objects obtained from this function inherit from the hierarchy, so before calling methods on these classes, always check whether the method is implemented on the class. The following code demonstrates how to use this function: Output: There are three ways to get a class definition: , , and . If the class is not registered at runtime, returns , while invokes a class handler callback and checks again; if still not found, it returns . behaves the same as except it kills the process if the class is not found. : if the specified class is not registered, the function invokes a class handler callback and checks again; if still not registered, it returns . However, every class definition must have a valid metaclass definition, so this function always returns a metaclass definition, whether or not it is valid. Code: All code from this post can be found on my GitHub .