Objective-C is a reflective, object-oriented programming language which adds Smalltalk-style messaging to C. Today it is used primarily on Mac OS X and GNUstep, two environments based on the OpenStep standard, and is the primary language used for the NeXTSTEP, OPENSTEP, and Cocoa application frameworks. Generic Objective-C programs which do not make use of these libraries can also be compiled for any system supported by gcc, which includes an Objective-C compiler.
HistoryIn the early 1980s, common software engineering practice was based on structured programming. Structured programming was implemented in order to help "break down" programs into smaller parts, primarily to make them easier to work on as they grew increasingly large. However, as the problems being solved grew in size, structured programming became less useful as more and more procedures had to be written, leading to complex control structures and a low level of code reuse. Many saw object-oriented programming as a potential solution to the problem. In fact, Smalltalk had already addressed many of these engineering issues: some of the most complex systems in the world were Smalltalk environments.citation needed On the downside, Smalltalk used a virtual machine. The virtual machine interpreted an object memory called an image, containing all development tools. The Smalltalk image was very large and tended to require huge amounts of memory for the time and ran very slowly, partly due to the lack of useful hardware vm/container support. Objective-C was created primarily by Brad Cox and Tom Love in the early 1980s at their company Stepstone. Both had been introduced to Smalltalk while at ITT’s Programming Technology Center in 1981. Cox had become interested in the problems of true reusability in software design and programming. He realized that a language like Smalltalk would be invaluable in building powerful development environments for system developers at ITT. Cox began by modifying the C compiler to add some of the capabilities of Smalltalk. He soon had a working implementation of an object-oriented extension to the C language which he called "OOPC" for Object-Oriented Programming in C. Love, meanwhile, was hired by Schlumberger Research in 1982 and had the opportunity to acquire the first commercial copy of Smalltalk-80, which further influenced development of their brainchild. In order to demonstrate that real progress could be made, Cox showed that making interchangeable software components really needed only a few practical changes to existing tools. Specifically, they needed to support objects in a flexible manner, come supplied with a usable set of libraries, and allow for the code (and any resources needed by the code) to be bundled into a single cross-platform format. Cox and Love eventually formed a new venture, Productivity Products International (PPI), to commercialize their product, which coupled an Objective-C compiler with powerful class libraries. In 1986, Cox published the main description of Objective-C in its original form in the book Object-Oriented Programming, An Evolutionary Approach. Although he was careful to point out that there is more to the problem of reusability than just the language, Objective-C often found itself compared feature for feature with other languages. Popularization through NeXTIn 1988, NeXT, the company started by Steve Jobs after Apple, licensed Objective-C from StepStone (the owner of the Objective-C trademark) and released their own Objective-C compiler and libraries on which the NeXTstep user interface and interface builder were based. Although the NeXT workstations failed to make much of an impact in the marketplace, the tools were widely lauded in the industry. This led NeXT to drop hardware production and focus on software tools, selling NeXTstep (and OpenStep) as a platform for custom programming. The GNU project started work on their free clone of NeXTStep, named GNUstep, based on the OpenStep standard. Dennis Glatting wrote the first gnu-objc runtime in 1992. The GNU Objective-C runtime which has been in use since 1993 is the one developed by Kresten Krab Thorup when he was a university student in Denmark. Kresten also worked at NeXT from 1993-1996. After acquiring NeXT in 1996, Apple used OpenStep in its new operating system, Mac OS X. This included Objective-C and NeXT's Objective-C based developer tool, Project Builder (later replaced by Xcode), as well as its interface design tool, Interface Builder. Most of Apple's present-day Cocoa API is based on OpenStep interface objects, and is the most significant Objective-C environment being used for active development. SyntaxObjective-C is a very thin layer on top of C. Objective-C is a strict superset of C. That is, it is possible to compile any C program with an Objective-C compiler. Objective-C derives its syntax from both C and Smalltalk. Most of the syntax (including preprocessing, expressions, function declarations, and function calls) is inherited from C, while the syntax for object-oriented features was created to enable Smalltalk-style messaging. MessagesObjective-C syntax offers alternatives to a few 'kludges' in C syntax but more importantly supports object-oriented programming. The Objective-C model of object-oriented programming is based on sending messages to sovereign (even self-correcting) objects. This is unlike the Simula programming model used by C++ and this distinction is semantically important. The basic difference is that in Objective-C one does not call a method; one sends a message. In Objective-C the 'receiver' of a message can opt to refuse it. Both styles carry their own strengths and weaknesses. Simula style OOP allows multiple inheritance and faster execution by using compile-time binding whenever possible but does not support dynamic binding by default. It also forces all methods to have a corresponding implementation unless they are virtual but still, cannot be called unless an implementation is given. Smalltalk OOP allows messages to go unimplemented and is dynamically bound (see Dynamic Binding) but in some cases runs slower and some programmers (especially ones from simula based languages) feel that it is a hassle to debug. On that note, some Simula style programmers hate Objective-C while Objective-C (Smalltalk style) programmers hate Simula style languages and feel that they are not "true" object-oriented languages or that they are severely flawed (notably, C++ is the most attacked: for more information, see C++ FQA Lite). An object obj with method method is said to 'respond' to the message method. Sending the message method to obj would require the following code in C++. obj.method(parameter); Which in Objective-C is written as follows. obj method:parameter; This mechanism allows messages to be sent to an object defined first at runtime - something statically typed languages such as C++ are incapable of per the current standards for such languages. C++ will be able to support messaging per ANSI Standard if the Boost library is standardized. Qt provides this capability to C++ and other languages (but Objective-C is poorly supported) by adding the "connect" function as well as a large array of classes that afford and support this functionality. (Also See the dynamic typing section below for more advantages of dynamic (late) binding.) Objective C has a few features in message passing that relates to how it handles OO. Objective C messages do not need to execute because they are dynamically bound. If a message is implemented by an object, it will execute, but if not, it will not execute, yet the code will still compile and run. So for example, Every object is sent an "awakeFromNib" message... but those objects don't necessarily have to implement "awakeFromNib" to compile, if an object does implement "awakeFromNib", then that code will be executed when the message is sent, otherwise the message is ignored. Messages can also be sent to the object that implements them or to the superclass that an object is derived from. These can be accessed using the "self" and "super" object pointers. Also, messages can be sent to nil objects. Interfaces and implementationsObjective-C requires the interface and implementation of a class be in separately declared code blocks. By convention, the interface is put in a header file and the implementation in a code file; the header files, normally suffixed .h, are similar to C header files; the implementation (method) files, normally suffixed .m, can be very similar to C code files. InterfaceThe interface of the class is usually defined in a header file. A common convention is to name the header file after the name of the class. The interface for class Class would thus be found in the file Class.h. The interface declaration of the form: @interface classname : superclassname { // instance variables } +classMethod1; +(return_type)classMethod2; +(return_type)classMethod3:(param1_type)parameter_varName; -(return_type)instanceMethod1:(param1_type)param1_varName :(param2_type)param2_varName; -(return_type)instanceMethod2WithParameter:(param1_type)param1_varName andOtherParameter:(param2_type)param2_varName; @end Plus signs denote class methods, minus signs denote instance methods. Class methods have no access to instance variables. Return types can be any standard C type, a pointer to a generic Objective-C object, or a pointer to a specific type of object such as NSArray *, NSImage *, or NSString *. The default return type is the generic Objective-C type id. Method arguments begin with a colon followed by the expected argument type in parentheses followed by the argument name. In some cases (eg when writing system APIs) it is useful to add descriptive text before each parameter. -(void) setRange:(int)start :(int)end; -(void) importDocumentWithName:(NSString *)name withSpecifiedPreferences:(Preferences *)prefs beforePage:(int)insertPage; ImplementationThe interface only declares the class interface and not the methods themselves; the actual code is written in the implementation. Implementation (method) files normally have the file extension .m. @implementation classname +classMethod { // implementation } -instanceMethod { // implementation } @end Methods are written as with their interface declarations. Comparing C and Objective-C: int function(int i) { return square_root(i); } -(int)method:(int)i { return self square_root: i; } The syntax allows pseudo-naming of arguments. -(int)changeColorToRed:(float)red green:(float)green blue:(float)blue myColor changeColorToRed:5.0 green:2.0 blue:6.0; Internal representations of this method vary between different implementations of Objective-C. If myColor is of the class Color, internally, instance method -changeColorWithRed:green:blue: might be labeled _i_Color_changeColorWithRed_green_blue. The i is to refer to an instance method, with the class and then method names appended, colons translated to underscores. As the order of parameters is part of the method name, it cannot be changed to suit coding style or expression as in true named parameters. However, internal names of the function are rarely used directly, and generally messages are converted to function calls defined in the Objective-C runtime library - it's not necessarily known at link time which method will be called: the class of the receiver (the object being sent the message) need not be known until runtime. InstantiationOnce an Objective-C class is written, it can be instantiated. This is done by first allocating the memory for a new object and then by initializing it. An object isn't fully functional until both steps have been completed. These steps are typically accomplished with a single line of code: MyObject * o = MyObject alloc init; The alloc call allocates enough memory to hold all the instance variables for an object, and the init call can be overridden to set instance variables to specific values on creation. The init method is often written as follows: -(id) init { self = super init; if (self) { ivar1 = value1; ivar2 = value2; . . . } return self; } ProtocolsObjective-C was extended at NeXT to introduce the concept of multiple inheritance of specification, but not implementation, through the introduction of protocols. This is a pattern achievable either as an abstract multiply inherited base class in C++, or else, more popularly, adopted (e.g., in Java or C#) as an "interface". Objective-C makes use of both ad-hoc protocols, called informal protocols, and compiler enforced protocols called formal protocols. An informal protocol is a list of methods which a class can implement. It is specified in the documentation, since it has no presence in the language. Informal protocols often include optional methods, where implementing the method can change the behavior of a class. For example, a text field class might have a delegate which should implement an informal protocol with an optional autocomplete method. The text field discovers whether the delegate implements that method (via reflection), and, if so, calls it to support autocomplete. A formal protocol is similar to an interface in Java or C#. It is a list of methods which any class can declare itself to implement. Versions of Objective-C before 2.0 required that a class must implement all methods in a protocol it declares itself as adopting; the compiler will emit an error if the class does not implement every method of its declared protocols. However, Objective-C 2.0 added support for marking certain methods in a protocol optional; the compiler will not enforce that such methods are implemented. The Objective-C concept of protocols is different from the Java or C# concept of interfaces in that a class may implement a protocol without being declared to implement that protocol. The difference is not detectable from outside code. Formal protocols cannot provide any implementations, they simply assure callers that classes which conform to the protocol will provide implementations. In the NeXT/Apple library, protocols are frequently used by the Distributed Objects system to represent the capabilities of an object executing on a remote system. The syntax @protocol Locking - (void)lock; - (void)unlock; @end denotes that there is the abstract idea of locking which is useful, and when stated in a class definition @interface SomeClass : SomeSuperClass <Locking> @end denotes that instances of SomeClass will provide an implementation for the two instance methods using whatever means they want. This abstract specification is particularly useful to describe the desired behaviors of plug-ins for example, without constraining at all what the implementation hierarchy should be. Dynamic typingObjective-C, like Smalltalk, can use dynamic typing; an object can be sent a message that is not specified in its interface. This can allow for increased flexibility — in Objective-C an object can "capture" this message, and depending on the object, can send the message off again to a different object (who can respond to the message correctly and appropriately, or likewise send the message on again). This behavior is known as message forwarding or delegation (see below). Alternatively, an error handler can be used instead, in case the message cannot be forwarded. If the object does not forward the message, handle the error, or respond to it, a runtime error occurs. Static typing information may also optionally be added to variables. This information is then checked at compile time. In the following statements, increasingly specific type information is provided. The statements are equivalent at runtime, but the additional information allows the compiler to warn the programmer if the passed argument does not match the type specified. In the first statement, the object may be of any class. In the second statement, the object must conform to the aProtocol protocol, and in the third, it must be a member of the NSNumber class. - setMyValue:(id) foo; - setMyValue:(id <aProtocol>) foo; - setMyValue:(NSNumber*)foo; Dynamic typing can be a powerful feature. When implementing container classes using statically-typed languages without generics like pre-1.5 Java, the programmer is forced to write a container class for a generic type of object, and then cast back and forth between the abstract generic type and the real type. Casting however breaks the discipline of static typing – if you put in an Integer and read out a String, you get an error. One way of alleviating the problem is to resort to generic programming, but then container classes must be homogeneous in type. This need not be the case with dynamic typing. ForwardingSince Objective-C permits the sending of a message to an object which might not respond to it, the object has a number of things it can do with the message. One of these things could be to forward the message on to an object which can respond to it. Forwarding can be used to implement certain design patterns, such as the Observer pattern or the Proxy pattern very simply. The Objective-C runtime specifies a pair of methods in Object
- (retval_t) forward:(SEL) sel :(arglist_t) args; // with GCC - (id) forward:(SEL) sel :(marg_list) args; // with NeXT/Apple systems
- (retval_t) performv:(SEL) sel :(arglist_t) args; // with GCC - (id) performv:(SEL) sel :(marg_list) args; // with NeXT/Apple systems and as such an object wishing to implement forwarding needs only to override the forwarding method to define the forwarding behaviour. The action methods performv:: need not be overridden as this method merely performs the method based on the selector and arguments. ExampleHere is an example of a program which demonstrates the basics of forwarding.
#import <objc/Object.h> @interface Forwarder : Object { id recipient; //The object we want to forward the message to. } //Accessor methods - (id) recipient; - (id) setRecipient:(id) _recipient; @end
#import "Forwarder.h" @implementation Forwarder - (retval_t) forward: (SEL) sel : (arglist_t) args { /* * Check whether the recipient actually responds to the message. * This may or may not be desirable, for example, if a recipient * in turn does not respond to the message, it might do forwarding * itself. */ if(recipient respondsTo:sel) return recipient performv: sel : args; else return self error:"Recipient does not respond"; } - (id) setRecipient: (id) _recipient { recipient = _recipient; return self; } - (id) recipient { return recipient; } @end
#import <objc/Object.h> // A simple Recipient object. @interface Recipient : Object - (id) hello; @end
#import "Recipient.h" @implementation Recipient - (id) hello { printf("Recipient says hello!\n"); return self; } @end
#import "Forwarder.h" #import "Recipient.h" int main(void) { Forwarder *forwarder = Forwarder new; Recipient *recipient = Recipient new; forwarder setRecipient:recipient; //Set the recipient. /* * Observe forwarder does not respond to a hello message! It will * be forwarded. All unrecognized methods will be forwarded to * the recipient * (if the recipient responds to them, as written in the Forwarder) */ forwarder hello; return 0; } NotesIf we were to compile the program, the compiler would report $ gcc -x objective-c -Wno-import Forwarder.m Recipient.m main.m -lobjc main.m: In function `main': main.m:12: warning: `Forwarder' does not respond to `hello' $ The compiler is reporting the point made earlier, that Forwarder does not respond to hello messages. In certain circumstances, such a warning can help us find errors, but in this circumstance, we can safely ignore this warning, since we have implemented forwarding. If we were to run the program $ ./a.out Recipient says hello! CategoriesCox’s main concern was the maintainability of large code bases. Experience from the structured programming world had shown that one of the main ways to improve code was to break it down into smaller pieces. Objective-C borrowed and extended the concept of Categories to help with this process from Smalltalk implementations (e.g., see 1). A category collects method implementations into separate files. The programmer can place groups of related methods into a category to make them more readable. For instance, one could create a "SpellChecking" category "on" the String object, collecting all of the methods related to spell checking into a single place. Furthermore, the methods within a category are added to a class at runtime. Thus, categories permit the programmer to add methods to an existing class without the need to recompile that class or even have access to its source code. For example, if the system you are supplied with does not contain a spell checker in its String implementation, you can add it without modifying the String source code. Methods within categories become indistinguishable from the methods in a class when the program is run. A category has full access to all of the instance variables within the class, including private variables. Categories provide an elegant solution to the fragile base class problem for methods. If you declare a method in a category with the same method signature as an existing method in a class, the category’s method is adopted. Thus categories can not only add methods to a class, but also replace existing methods. This feature can be used to fix bugs in other classes by rewriting their methods, or to cause a global change to a class’ behavior within a program. If two categories have methods with the same method signature, it is undefined which category’s method is adopted. Other languages have attempted to add this feature in a variety of ways. TOM took the Objective-C system a step further and allowed for the addition of variables as well. Other languages have instead used prototype oriented solutions, the most notable being Self. Example usage of categoriesThis example builds up an Integer class, by defining first a basic class with only accessor methods implemented, and adding two categories, Arithmetic and Display, which extend the basic class. Whilst categories can access the base class’ private data members, it is often good practice to access these private data members through the accessor methods, which helps keep categories more independent from the base class. This is one typical usage of categories—the other is to use categories to add or replace certain methods in the base class (however it is not regarded as good practice to use categories for subclass overriding).
#import <objc/Object.h> @interface Integer : Object { int integer; } - (int) integer; - (id) integer: (int) _integer; @end
#import "Integer.h" @implementation Integer - (int) integer { return integer; } - (id) integer: (int) _integer { integer = _integer; return self; } @end
#import "Integer.h" @interface Integer (Arithmetic) - (id) add: (Integer *) addend; - (id) sub: (Integer *) subtrahend; @end
#import "Arithmetic.h" @implementation Integer (Arithmetic) - (id) add: (Integer *) addend { return self integer: self integer + addend integer; } - (id) sub: (Integer *) subtrahend { return self integer: self integer - subtrahend integer; } @end
#import "Integer.h" @interface Integer (Display) - (id) showstars; - (id) showint; @end
#import "Display.h" @implementation Integer (Display) - (id) showstars { int i, x = self integer; for(i=0; i < x; i++) printf("*"); printf("\n"); return self; } - (id) showint { printf("%d\n", self integer); return self; } @end
#import "Integer.h" #import "Arithmetic.h" #import "Display.h" int main(void) { Integer *num1 = Integer new, *num2 = Integer new; int x; printf("Enter an integer: "); scanf("%d", &x); num1 integer:x; num1 showstars; printf("Enter an integer: "); scanf("%d", &x); num2 integer:x; num2 showstars; num1 add:num2; num1 showint; } NotesCompilation is performed, for example, by gcc -x objective-c main.m Integer.m Arithmetic.m Display.m -lobjc One can experiment by omitting the #import "Arithmetic.h" and [num1 add:num2] lines and omit Arithmetic.m in compilation. The program will still run. This means that it is possible to "mix-and-match" added categories if necessary – if one does not need to have some capability provided in a category, one can simply not compile it in. PosingObjective-C permits a class to wholly replace another class within a program. The replacing class is said to "pose as" the target class. Note: Class posing was declared deprecated with Mac OS X v10.5 and unavailable in the 64-bit runtime. For the versions still supporting posing: All messages sent to the target class are instead received by the posing class. There are several restrictions:
Posing, similarly to categories, allows globally augmenting existing classes. Posing permits two features absent from categories:
For example, @interface CustomNSApplication : NSApplication @end @implementation CustomNSApplication - (void) setMainMenu: (NSMenu*) menu { // do something with menu } @end class_poseAs (CustomNSApplication class, NSApplication class); This intercepts every invocation of setMainMenu to NSApplication.
| ||||||||||||||||||||||||||||||||||||
|
||||||||||||||