Objective-C is a super set of C language. The entire language is a preprocessor skin added to C language and a powerful runtime system. With this runtime system, one can have full featured object oriented programming interface, functional programming environment, and magical dynamic typing system.
In this post, I’ll go through common tasks you can do with Objective-C typing
system, including querying normal
NSObject types, packing static type with
NSValue, testing core foundation references, and validating if a pointer is a
valid object pointer.
Objective-C type system
To determine an Objective-C object type is super easy. Just use
method and it is done.
1 2 3 4 5 6 7 8
Why do we need this mechanism? One application is implementing key value coding with some known range of types. For example, Core Animation listed these properties are animatable:
These properties are categorized in several types includes
CGColorRef, and even
BOOL. Each kind of type
require individual implementation to operate its value. Thankfully,
Objective C dynamic type system allows us to pass-in the value with generic type
id and determine the actual type at runtime.
id is simply a void
pointer. The objective c object itself is a struct which have a
points to actual class which defines its instance variables, methods, and class
Packaging static C types with NSValue
Objective C is a skin language based on C, so it is very often to use C types
like int, float, pointer to struct…etc. However, these static types violate
Objective-C’s dynamic typing idioms. Apple introduced
NSValue as a container
for a single C or Objective-C data item. It can hold any C types such as int,
float, char, pointers, structures, and object ids. It not only wrap the item
into an Objective-C object, but also encode the type information of the original
To create an
NSValue object, you pass it a pointer to the item, along with the
encoded type information generated by
@encode() is a compiler directive which can accepts all types that can be used
as an argument of C
@encode() returns a
string encoding that type. The encoding is specified in
Objective-C runtime type encodings.
To illustrate this, see the following examples:
1 2 3 4 5 6 7 8
With this encoded type information, it only takes few steps to determine which type it is at runtime:
1 2 3 4 5 6 7 8
UIKit addition to NSValue
UIKit added a category for NSValue to represent iOS related
geometry-based data. You can use these method instead of encoding
CGRect, and else every time.
Bridging with Core Foundation objects
NSValue covers many kind of types, in practice there are still some
types don’t fit this solution for dynamic typing. More specifically,
CGImageRef and other Core Foundation types that can be treated
as Objective-C object through toll-free briding are the types we
don’t pack with
A core foundation references is also a void pointer as same as
To find out the type of an unknown
CFTypeRef, you can query it with C function
1 2 3 4 5
A CFTypeRef marked as
id type can also accept basic objective C messages like
isKindOfType:. Hence testing an
id typed object is quite safe as long as it
is either a
CGColorRef or any other
Objective-C object/Core Foundation reference.
Testing if a pointer is a valid NSObject
There is a blog post on Cocoa with love about how to test if an arbitary pointer is a valid NSObject. In my point of view, programmer should pass in a valid object for sure. If it is not a valid object, just let it crash.
Puting it all together
This piece of code is part of my project FCAnimationFactory for the purpose of interpolating different kinds of value with respect to their types.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
It is amazing that a langauge so close to C can create such a rich type system without byte code, VM, or complex sybol tricks (like what C++ does). Though handling differnt types can be a bit painful sometimes, but it brings powerful polimorphsm to the language. Thus programmer can create highly abstract API and framework with differnt data types that share the same methods.