Cocoa Dev Central Learn Objective-C

Embed Size (px)

Citation preview

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    1/11

    Learn Objective-C Page 1

    Cocoa Dev Central

    Objective-C

    Objective-C is the primary language used to write Mac software. If you'recomfortable with basic object-oriented concepts and the C language, Objective-Cwill make a lot of sense. If you don't know C, you should read the C Tutorialfirst.

    This tutorial is written and illustrated by Scott Stevenson

    Copyright 2008 Scott Stevenson

    1 Calling Methods

    To get started as quickly as possible, let's look at some simple examples. Thebasic syntax for calling a method on an object is this:

    [objectmethod]; [objectmethodWithInput:input];Methods can return a value:

    output = [objectmethodWithOutput]; output = [objectmethodWithInputAndOutput:input];You can call methods on classes too, which is how you create objects. In theexample below, we call the string method on the NSString class, which returns anew NSString object:

    idmyObject = [NSString string];The idtype means that themyObject variable can refer to any kind of object, sothe actual class and the methods it implements aren't known when you compile theapp.

    In this example, it's obvious the object type will be an NSString, so we canchange the type:

    NSString* myString = [NSString string];This is now an NSString variable, so the compiler will warn us if we try to use a

    method on this object which NSString doesn't support.

    Notice that there's a asterisk to the right of the object type. All Objective-Cobject variables are pointers types. The idtype is predefined as a pointer type,so there's no need to add the asterisk.

    Nested Messages

    http://cocoadevcentral.com/http://cocoadevcentral.com/articles/000081.phphttp://theocacao.com/http://theocacao.com/http://cocoadevcentral.com/articles/000081.phphttp://cocoadevcentral.com/
  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    2/11

    Learn Objective-C Page 2

    In many languages, nested method or function calls look like this:

    function1 ( function2() );The result of function2 is passed as input to function1. In Objective-C, nestedmessages look like this:

    [NSString stringWithFormat:[prefs format]];Avoid nested nesting more than two message calls on a single line, as it easily

    gets unreadable.

    Multi-Input Methods

    Some methods take multiple input values. In Objective-C, a method name can besplit up into several segments. In the header, a multi-input method looks likethis:

    -(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;You call the method like this:

    BOOL result = [myData writeToFile:@"/tmp/log.txt" atomically:NO];These are not just named arguments. The method name is actuallywriteToFile:atomically: in the runtime system.

    2 AccessorsAll instance variables are private in Objective-C by default, so you should useaccessors to get and set values in most cases. There are two syntaxes. This isthe traditional 1.x syntax:

    [photo setCaption:@"Day at the Beach"]; output = [photo caption];The code on the second line is not reading the instance variable directly. It'sactually calling a method named caption. In most cases, you don't add the "get"prefix to getters in Objective-C.

    Whenever you see code inside square brackets, you are sending a message to anobject or a class.

    Dot Syntax

    The dot syntax for getters and setters is new in Objective-C 2.0, which is partof Mac OS X 10.5:

    photo.caption = @"Day at the Beach"; output = photo.caption;You can use either style, but choose only one for each project. The dot syntaxshould only be used setters and getters, not for general purpose methods.

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    3/11

    Learn Objective-C Page 3

    3 Creating Objects

    There are two main ways to create an object. The first is the one you saw before:

    NSString* myString = [NSString string];This is the more convenient automatic style. In this case, you are creating anautoreleasedobject, which we'll look at in more detail later. In many cases,though, you need to create an object using the manual style:

    NSString* myString = [[NSString alloc] init];This is a nested method call. The first is the alloc method called on NSString

    itself. This is a relatively low-level call which reserves memory andinstantiates an object.

    The second piece is a call to init on the new object. The init implementationusually does basic setup, such as creating instance variables. The details ofthat are unknown to you as a client of the class.

    In some cases, you may use a different version of init which takes input:

    NSNumber* value = [[NSNumber alloc] initWithFloat:1.0];

    4 Basic Memory Management

    If you're writing an application for Mac OS X, you have the option to enablegarbage collection. In general, this means that you don't have to think aboutmemory management until you get to more complex cases.

    However, you may not always be working with an environment that supports garbagecollection. In that case, you need to know a few basic concepts.

    If you create an object using the manual alloc style, you need to release the

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    4/11

    Learn Objective-C Page 4

    object later. You should not manually release an autoreleased object because yourapplication will crash if you do.

    Here are two examples:

    // string1 will be released automatically NSString* string1 = [NSString string];// must release this when done NSString* string2 = [[NSString alloc] init];[string2 release];

    For this tutorial, you can assume that an automatic object will go away at theend of the current function.

    There's more to learn about memory management, but it will make more sense afterwe look at a few more concepts.

    5 Designing a Class Interface

    The Objective-C syntax for creating a class is very simple. It typically comes intwo parts.

    The class interface is usually stored in the ClassName.h file, and definesinstance variables and public methods.

    The implementation is in the ClassName.m file and contains the actual code forthese methods. It also often defines private methods that aren't available toclients of the class.

    Here's what an interface file looks like. The class is called Photo, so the file

    is named Photo.h:

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; }@endFirst, we import Cocoa.h, to pull in all of the basic classes for a Cocoa app.The #import directive automatically guards against including a single filemultiple times.

    The@interface says that this is a declaration of the class Photo. The colonspecifies the superclass, which is NSObject.

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    5/11

    Learn Objective-C Page 5

    Inside the curly brackets, there are two instance variables: caption andphotographer. Both are NSStrings, but they could be any object type, includingid.

    Finally, the@endsymbol ends the class declaration.

    Add Methods

    Let's add some getters for the instance variables:

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; } - caption; -photographer; @endRemember, Objective-C methods typically leave out the "get" prefix. A single dashbefore a method name means it's a instance method. A plus before a method namemeans it's a class method.

    By default, the compiler assumes a method returns an id object, and that all

    input values are id. The above code is technically correct, but it's unusual.Let's add specific types for the return values:

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; } - (NSString*) caption; - (NSString*) photographer; @endNow let's add setters:

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; } - (NSString*) caption; - (NSString*) photographer; -(void) setCaption: (NSString*)input; - (void) setPhotographer: (NSString*)input;@endSetters don't need to return a value, so we just specify them as void.

    6 Class Implementation

    Let's create an implementation, starting with the getters:

    #import "Photo.h"@implementation Photo - (NSString*) caption { return caption; }- (NSString*) photographer { return photographer; }@endThis part of the code starts with@implementation and the class name, and has@end, just like the interface. All methods must appear between these two

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    6/11

    Learn Objective-C Page 6

    statements.

    The getters should look very familiar if you've ever written code, so let's moveon to the setters, which need a bit more explanation:

    - (void) setCaption: (NSString*)input { [caption autorelease]; caption = [inputretain]; } - (void) setPhotographer: (NSString*)input { [photographerautorelease]; photographer = [input retain]; }

    Each setter deals with two variables. The first is a reference to the existingobject, and the second is the new input object. In a garbage collectedenvironment, we could just set the new value directly:

    - (void) setCaption: (NSString*)input { caption = input; }But if you can't use garbage collection, you need to release the old object, andretain the new one.

    There are actually two ways to free a reference to an object: release andautorelease. The standard release will remove the reference immediately. Theautorelease method will release it sometime soon, but it will definitely stay

    around until the end of the current function (unless you add custom code tospecifically change this).

    The autorelease method is safer inside a setter because the variables for the newand old values could point to the same object. You wouldn't want to immediatelyrelease an object which you're about to retain.

    This may seem confusing right now, but it will make more sense as you progress.You don't need to understand it all yet.

    Init

    We can create an init method to set inital values for our instance variables:

    - (id) init { if ( self = [super init] ) { [self setCaption:@"Default Caption"];[self setPhotographer:@"Default Photographer"]; } return self; }This is fairly self-explanatory, though the second line may look a bit unusual.This is a single equals sign, which assigns the result of [super init] to self.

    This essentially just asks the superclass to do its own initialization. The if

    statement is verifying that the initialization was successful before trying toset default values.

    Dealloc

    The dealloc method is called on an object when it is being removed from memory.This is usually the best time to release references to all of your child instancevariables:

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    7/11

    Learn Objective-C Page 7

    - (void) dealloc { [caption release]; [photographer release]; [super dealloc]; }On the first two lines, we just send release to each of the instance variables.We don't need to use autorelease here, and the standard release is a bit faster.

    The last line is very important. We have to send the message[super dealloc] to ask the superclass to do its cleanup. If we don't do this, theobject will not be removed, which is a memory leak.

    The dealloc method is not called on objects if garbage collection is enabled.Instead, you implement thefinalize method.

    7 More on Memory ManagementObjective-C's memory management system is called reference counting. All you haveto do is keep track of your references, and the runtime does the actual freeingof memory.

    In simplest terms, you alloc an object, maybe retain it at some point, then sendone release for each alloc/retain you sent. So if you used alloc once and thenretain once, you need to release twice.

    That's the theory of reference counting. But in practice, there are usually onlytwo reasons to create an object:

    1. To keep it as an instance variable2. To use temporarily for single use inside a function

    In most cases, the setter for an instance variable should just autorelease theold object, and retain the new one. You then just make sure to release it indealloc as well.

    So the only real work is managing local references inside a function. And there'sonly one rule: if you create an object with alloc or copy, send it a release orautorelease message at the end of the function. If you create an object any otherway, do nothing.

    Here's the first case, managing an instance variable:

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    8/11

    Learn Objective-C Page 8

    - (void) setTotalAmount: (NSNumber*)input { [totalAmount autorelease];totalAmount = [input retain]; } - (void) dealloc { [totalAmount release]; [superdealloc]; }Here's the other case, local references. We only need to release the objectcreated with alloc:

    NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75]; NSNumber* value2 =[NSNumber numberWithFloat:14.78]; // only release value1, not value2 [value1

    release];And here's a combo: using a local reference to set an object as an instancevariable:

    NSNumber* value1 = [[NSNumber alloc] initWithFloat:8.75]; [self setTotal:value1];NSNumber* value2 = [NSNumber numberWithFloat:14.78]; [self setTotal:value2];[value1 release];Notice how the rules for managing local references are exactly the same,regardless of whether you're setting them as instance variables or not. You don'tneed to think about how the setters are implemented.

    If you understand this, you understand 90% of what you will ever need to knowabout Objective-C memory management.

    8 LoggingLogging messages to the console in Objective-C is very simple. In fact, theNSLog() function is nearly identical to the Cprintf() function, except there'san additional%@token for objects.

    NSLog ( @"The current date and time is:%@", [NSDate date] );

    You can log an object to the console. The NSLog function calls the descriptionmethod on the object, and prints the NSString which is returned. You can overridethe description method in your class to return a custom string.

    9 PropertiesWhen we wrote the accessor methods for caption and author earlier, you might havenoticed that the code is straightforward, and could probably be generalized.

    Properties are a feature in Objective-C that allow us to automatically generateaccessors, and also have some other side benefits. Let's convert the Photo class

    to use properties.

    Here's what it looked like before:

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; } - (NSString*) caption; - (NSString*) photographer; -(void) setCaption: (NSString*)input; - (void) setPhotographer: (NSString*)input;@endHere's what it looks like once converted to properties:

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    9/11

    Learn Objective-C Page 9

    #import @interface Photo : NSObject { NSString* caption;NSString* photographer; }@property (retain) NSString* caption;@property(retain) NSString*photographer; @endThe@property is an Objective-C directive which declares the property. The"retain" in the parenthesis specifies that the setter should retain the inputvalue, and the rest of the line simply specifies the type and the name of theproperty.

    Now let's take a look at the implementation of the class:

    #import "Photo.h" @implementation Photo@synthesize caption;@synthesizephotographer; - (void) dealloc { [caption release]; [photographer release];[super dealloc]; } @endThe@synthesize directive automatically generates the setters and getters for us,so all we have to implement for this class is the dealloc method.

    Accessors will only be generated if they don't already exist, so feel free tospecify @synthesize for a property, then implement your custom getter or setter

    if you want. The compiler will fill in whichever method is missing.

    There are many other options for the property declarations, but those are outsideof the scope of this tutorial.

    10Calling Methods on NilIn Objective-C, the nil object is the functional equivalent to the NULL pointerin many other languages. The difference is that you can call methods on nilwithout crashing or throwing an exception.

    This technique used by the frameworks in a number of different ways, but the mainthing it means to you right now that you usually don't need to check for nilbefore calling a method on an object. If you call a method on nil that returns anobject, you will get nil as a return value.

    We can also use this to improve our dealloc method slightly:

    - (void) dealloc { self.caption = nil; self.photographer = nil; [super dealloc];}This works because when we set nil as an instance variable, the setter justretains nil (which does nothing) and releases the old value. This approach isoften better for dealloc because there's no chance of the variable pointing atrandom data where an object used to be.

    Note that we're using the self. syntax here, which means we're using thesetter and picking up the memory management for free. If we just directly set thevalue like this, there would be a memory leak:

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    10/11

    Learn Objective-C Page 10

    // incorrect. causes a memory leak.// use self.caption to go through settercaption = nil;

    11CategoriesCategories are one of the most useful features of Objective-C. Essentially, acategory allows you to add methods to an existing class without subclassing it orneeding to know any of the details of how it's implemented.

    This is particularly useful because you can add methods to built-in objects. Ifyou want to add a method to all instances of NSString in your application, youjust add a category. There's no need to get everything to use a custom subclass.

    For example, if I wanted to add a method to NSString to determine if the contentsis a URL, it would look like this:

    #import @interface NSString (Utilities) - (BOOL) isURL;@endThis is very similar to a class declaration. The differences are that there is nosuper class listed, and there's a name for the category in parenthesis. The name

    can be whatever you want, though it should communicate what the methods insidedo.

    Here's the implementation. Keep in mind this is not a good implementation of URLdetection. We're just trying to get the concept of categories across:

    #import "NSString-Utilities.h"@implementation NSString (Utilities) - (BOOL)isURL { if ( [self hasPrefix:@"http://"] ) return YES; else return NO; }@endNow you can use this method on any NSString. The following code will print"string1 is a URL" in the console:

    NSString* string1 = @"http://pixar.com/"; NSString* string2 = @"Pixar"; if ([string1 isURL] ) NSLog (@"string1 is a URL"); if ( [string2 isURL] ) NSLog(@"string2 is a URL");Unlike subclasses, categories can't add instance variables. You can, however, usecategories to override existing methods in classes, but you should do so verycarefully.

    Remember, when you make changes to a class using a category, it affects allinstances of that class throughout the application.

    Wrap Up

    This is a basic overview of Objective-C. As you've seen, the language is prettyeasy to pick up. There's not much special syntax to learn, and the sameconventions are used over and over again throughout Cocoa.

    If you'd like these examples in action, download the project below and lookthrough the source code:

  • 7/30/2019 Cocoa Dev Central Learn Objective-C

    11/11

    Learn Objective-C Page 11

    LearnObjectiveC Xcode 3.0 Project (56k)

    Thank you.Cocoa Dev Central is a service mark of Tree House IdeasSite design 2004-2008 Scott Stevenson | Made with TextMate

    http://cocoadevcentral.com/downloads/LearnObjectiveC-20080414a.ziphttp://treehouseideas.com/http://macromates.com/http://macromates.com/http://treehouseideas.com/http://cocoadevcentral.com/downloads/LearnObjectiveC-20080414a.zip