Monday 7 December 2009

Objective-C Programming Language Summary

A summary by James Bedford.

Objective-C is an extension to the C programming language developed in the early 1980s. It is used in all Apple products including Mac and iPhone software development. Originally referred to as "C with messaging", the primary aim of Objective-C is to introduce object oriented programming to C, and achieves this using a different approach to C++ or C#.


I’ve got no time for messing about, so here’s s summary of the entire language, assuming you already understand object oriented programming (OOP) concepts and a thorough understanding of C (because I’m not going to explain anything that’s the same as C). Example code (as infrequent as it may be) is written between quotation marks. This may get a little confusing at times, so try and stick with it (maybe copying and pasting the inside of quotes may help). The example code will always be a single line of the program.

This page is also going to be updated as I continue to summarize the language. Please let me know if anything needs clarifying, or if there are any problems with the notes.

These notes are intended to be read with "Cocoa Framework Summary by James Bedford".

Here we go…



Objective-C is an extension to C



  • Any C code will work in an Objective-C program.

  • C data types and pointers are used in Objective-C and Cocoa programming.

  • C conventions are still used.

    • E.g. The main method is where program execution begins, and returns an int.






Writing Objective-C Programs



  • Code is saved in .m files, e.g. "HelloWorld.m" - 'm' originally stood for 'messages'.

  • #import <Directory/Example.h>

    • Pre-processor "import" statement means that this will only be included once. It means you don't have to use #ifdef couples with #include.



  • NSLog() is similar to printf(), but is more advanced.

    • It automatically adds the end-line character.

    • Must be passed an NSString.

    • The NSString may take the standard formatters, including %d, and introducing %@ for an object. When the %@ is reached, the corresponding object's description method is called, which should return an NSString.






New Data Types



  • BOOL

    • Stores a boolean value as "YES" or "NO".

    • Pre-dates C's bool type by a decade.

    • BOOL is just a typedef for a signed character (which uses 8 bits). Only the last bit determines the value of BOOL).



  • id

    • Can hold a pointer to any type of object.



  • NSString (a very common Object - see Cocoa notes).

    • NSString literal can be referenced using the @ shorthand. For example, "NSString message = @"Hello World!";"



  • NSArray (an enhanced array that supports objects - see Cocoa notes).

    • Can be traversed quickly using "for in".

    • e.g. "for (NSString * string in array) { // do something }"






Classes and Objects



  • Defined using two sections, which make up a class (the interface and the implementation). These sections are normally implemented in two separate files, a .h (header) file for the interface, and a .m (source code) file for the implementation. The implementation imports the header file.

    • Header files are referred to as 'interface files' and source code files are referred to as 'implementation files'.



  • Interface

    • The API of the class. Declares what's going to be in it and defines the class.

    • @interface declares that this is the interface of a class, followed by the class name, followed by a colon, followed by the object that this class inherits. If the object being defined doesn't inherit a class, it must be defined to inherit NSObject.

      • Example: "@interface SkyScraper : Building".

      • Notes on inheritance:

        • Objective-C does not support multiple inheritance, but this can be worked around using 'categories' and 'protocols'.

        • A class that is a child of another has all the properties and methods of it's parent class.

        • You can override inherited methods be redefining a method in the subclass.

        • You can reference the superclass from the subclass using the super keyword. For example, "[super findGreatestSize];"

        • When using the init method of a subclass, it is very wise to make a call to the superclass's init method, and check that this returns ok using the line, "if ([super init])" then follow code. This ensures that the superclass does everything it should before the subclass adds its bit. This is assigned to self so that the subclass has everything the superclass would already have. This is then checked by the if statement to ensure everything is ok, before the subclass init method initialises subclass specific stuff.





    • This is then followed by a pair of matching curly braces. Instance variables are declared within the curly braces, e.g. "int age = 20;"

    • Methods declarations follow, and are of the format:

      • <method declaration symbol>

        • Either a + or a -, denoting a class method, or an instance method respectively.



      • <return type>

        • Any type, can be void.

        • Must be within brackets.



      • <name>

        • Must be followed by a colon.



      • <optional method parameters>

        • Type first (which must be within brackets), followed by a variable name.



      • <further optional parameters>

        • Objective-C uses infix notation. This means that the name of the method, and it's arguments, are mixed.

        • You must follow a second (and further) method arguments with the names of arguments.

        • So you must repeat <name> and <optional method parameters> for each argument.

        • For example, a method with three arguments would defined as follows:

          • "- (Circle) generateCircleWithColor: (NSColor) rColor ofSize: (NSSize) rSize withTest: (NSString) rTest;"

          • Notice the types are in brackets.



        • "…" (ellipses) can be used to tell the compiler that the method takes any number of additional arguments, separated by commas. (The stringWithFormat method in NSString uses this).



      • <semicolon>

      • For example:

        • "- (void) setBookColor: (NSColor) rColor;"



      • The word "get" precedes a method conventionally, and is used to mean that this method requires pointers are parameters, so don't use it for accessor methods (getters).

      • Mutator methods (setters) should proceed with the word "set" conventionally.



    • The interface is ended with the @end notation.



  • Implementation

    • Puts meat on the bones. This is where the actual code for the class is.

    • @implementation declares the start of the implementation section.

    • For each method you wish to code, you must declare which method you wish, then write the code between two curly braces.

    • You don't finish these methods with a semicolon, as the methods don't need to be declared - this was done in the interface.

    • You can define a method in the implementation and not in the interface. There's no private methods, so it can still be accessed, but it won't be documented in the API (interface).

    • Example:

      • "- (void) setBookColor: (NSColor) rColor { bookColor = rColor; }"





  • Always reference objects by using pointers.

  • Sending objects messages - i.e. calling methods.

    • Done using square brackets.

    • E.g. "[goodBook setTitle: popularTitle];"

      • Where 'goodBook' is an instance of a class, say, Book, setTitle is an instance method of the class Book, and 'popularTitle' is a variable that is of the type requested by the method setTitle.



    • A method call (message send) can be made to any object. This is known as dynamic typing, and has the advantage that types can be unknown at compile time, but runs the risk of run-time errors, should a message be sent to an object that doesn't have such a method within it. At the time of writing, my understanding of this is that exception handling must be put into place if there's a possibility that the object won't have the method.



  • Instantiating objects:

    • Send the new message! e.g. "Class * instance = [Class new];"

    • The method new allocates memory and initialises a new instance of a class, and is a short hand for: "[[Class alloc] init ];" It returns a pointer to this new instance of the class.

    • These methods are all class methods.

    • The returned object has a retain count of 1 and is not autoreleased (see memory management).



  • @class

    • Is used to set up a forward reference (or forward declaration), which tells the compiler that such a class does exist, and that it'll find out about it in the future.

    • Example use: if a Class is composed of another class (or classes). Use the @class before the @interface declaration in order to let the compiler know it'll find out more later.

    • e.g "@class Brick;"

    • However, if more than just the class name is being used (e.g. instance variables or methods), then that class must be imported.



  • Properties

    • Introduced in Objective-C 2.0

    • @property (parameters) <TYPE> <variable name>;

      • Used in the @interface section.

      • INCOMPLETE NOTES



    • @synthesize

      • Used in the @implementation section. This automatically creates methods as required (stated in the corresponding @property).





  • Copying/Duplicating Objects

    • See 'NSCopying' under protocols.






Objective-C Runtime:



  • Creates an object for each class, known as a class object.

    • This object holds pointers to the superclass, class name, class methods, and holds a long which specifies how much memory needs to be allocated to store an instance of the class.






Message/Method Dispatch System:



  • Part of the Objective-C runtime code.

  • A message is sent using square brackets [ and ] as follows:

    • "[ boat sailFromShoreTo: america ];"



  • The message is sent to the object boat, which is of type Boat, so the message goes to the class to look up the method sailFromShoreTo. If this method is not found in Boat, then the dispatch system moves to the superclass, and searches for the method there.

  • If the dispatch system reaches the highest object in the hierarchy and still doesn't find, then some serious problems may occur…




Memory Management:



  • Cocoa uses reference counting (also known as retain counting).

  • Every object has an integer reference count (also know as a retain count).

  • When code wants to use an object it increments the retain count, and when it's finished with it, it decrements it.

  • When the retrain count reaches 0 the object is destroyed using dealloc (Objective-C will do this, don't ever call this directly).

  • Objects created using alloc, new or copy have a retrain count of 1.

  • retain - increments the retain count. Returns a pointer to the object so you can chain message sends.

  • release - decrements the retain count. Void method.

  • retainCount - returns the retain count.

  • Object ownership - when code starts using an object it should retain it, and release it when it's finished using it.

  • Mutator methods - one way of handling memory management when setting an object in composition is to - retrain the new object, then release the old, then set.

  • Autorelease pool

    • NSAutoreleasePool

    • A collection of objects that automatically get released.

    • autorelease - puts an object into an NSAutoreleasePool.

    • When the pool is destroyed (using release to get to a retain count of 0), it sends release messages to all the objects in the pool.

    • drain - empties the pool (releases all the objects) without destroying the pool.

    • When you create an NSAutoreleasePool, it becomes the default pool all the objects go into.



  • Cocoa Memory Management Rules:

    • A newly created object (an object created using the alloc, copy or new methods) has a retrain count of 1. The programmer is responsible for cleaning up this object.

    • Retrieving an object via another mechanism - assume it has a retain count of 1 and is set to autorelease. Retrain and release it if you're going to use it for a while.

    • Always balance retains and releases.



  • Garbage collection

    • Is possible since Objective-C 2.0. Just needs to be enabled on the compiler.

    • Once enabled, all the memory management instructions are just ignored and the garbage collector is used.

    • Garbage collection can't be used on the iPhone.






Formal Protocols:



  • Definition:

    • A named list of methods.

    • When adopting a protocol, you're agreeing to supply these methods (and have to otherwise you'll get a compiler error).

    • Similar to Java interfaces.



  • How to adopt a protocol:

    • This is done in the @interface section of the class, using the following format:

    • @interface className : Subclass <adoptsThisProtocol, andThisProtocol>

    • The name of the protocol you wish to adopt follows within matching < and >. Multiple protocols are separated by commas.

    • Protocols are inherited.



  • Declaring protocols:

    • @protocol <NAME>

      • Start a protocol definition with this declaration.

      • Must have a unique name.



    • Define as many methods as necessary using the usual method declaration rules. These methods will need to be implemented by a class that adopts this protocol.

    • @optional

      • Objective-C 2.0

      • Used before declaring methods that a class can optionally implement.



    • @required

      • Objective-C 2.0

      • Used before declaring methods that a class has to implement.



    • @end

      • Ends the definition of the protocol.





  • Using protocols with data types:

    • Protocols can be used to specify objects.

    • This is achieved using the id data type, followed by the protocols that have to be implemented. For example:

    • "- (void) methodName: (id<NSCopying>) objectName ".

    • This method will take any object that implements the NSCopying protocol, if it doesn't implement this protocol, the complier will give a warning.



  • Example/Useful Protocols:

    • NSCopying

      • Declares the following method:

      • " - (id) copyWithZone: (NSZone *) zone "

        • The method copy deals with the NSZone and calls this method. When using this copy method, send the copy message.

        • The (NSZone *) parameter comes from old Objective-C programming. An NSZone is a location in memory that can be used for the copying (I think).



      • Deep copy implementation for a class:

        • Make a pointer to a class.

        • Make this pointer point to [[[self class] allocWithZone: zone] init];

        • The method class returns the class of the current object. If this class is extended then the copy method will still work correctly.

        • The method allocWithZone allocates memory for a new object (like alloc) using an NSZone provided.

        • The method init is called to initialises the object.

          • A specific initialiser method can be used, passing it the values of the object-to-be-copied to initialise with.

          • Or setters can be used to make the new object the same as the old one.

          • The . operator can be used to access any variable. A copy method can make good, appropriate use of this operator.



        • Return the pointer originally made. (This object has a retain count of 1 due to the allocWithZone method).

        • For subclasses, call [super copyWithZone: zone] before doing subclass specific copying instead of calling [[self class] allocWithZone: zone] init ].










Categories:



  • INITIAL QUICK NOTES:

    • A way of adding methods to existing classes.

    • An informal protocol.




That's all for now! :)

3 comments:

  1. [...] first post attempts to begin summarising the Objective-C programming language, a language used to write applications for the Apple Mac and [...]

    ReplyDelete
  2. [...] notes are intended to be read with “Objective-C Programming Language Summary by James Bedford” as well as the Apple Developer [...]

    ReplyDelete