learn objetive-c

时间:2023-12-27 10:12:37

Cocoa Dev Central

Objective-C

Objective-C is the primary language used to write Mac software. If you're comfortable with basic object-oriented concepts and the C language, Objective-C will make a lot of sense. If you don't know C, you should read the C Tutorial first. 
objective-c 是用于开发mac软件的主要语言。如果你熟悉面向对象思想和c语言,那么objective-c将简单。如果你没学过c,那你应该先去看下c的教程。

Copyright © 2008 Scott Stevenson

1

Calling Methods

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

为了能够更快的上手,让我们先来看一些简单的例子吧。下面的基本的对象调用函数方法:

[object method];

[object methodWithInput:input];

Methods can return a value:

将返回一个值:

output = [object methodWithOutput];

output = [object methodWithInputAndOutput:input];

You can call methods on classes too, which is how you create objects. In the example below, we call the string method on the NSString class, which returns a new NSString object:

你也可以使用类直接调用方法。实际如在NSString类中直接调用string方法,返回一个NSString的对象:

id myObject = [NSString string];

The id type means that the myObject variable can refer to any kind of object, so the actual class and the methods it implements aren't known when you compile the app. 
id类型表示myobject变量能够是任意类型,所以事实上在编译的时候系统并不知道其是什么类型。

在这个例子中,我们可以知道该类型是NSString,所以我们可以改为:
In this example, it's obvious the object type will be an NSString, so we can change 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. 
表明是NSSting类型后,如果我们调用了一个NSString没有的方法编译的时候将会直接收到警告。

请注意的是关于对象类型,所有的objective-c对象都是指针类型。Id已被预定义为了一个指针类型,所以并没有警告提示。
Notice that there's a asterisk to the right of the object type. All Objective-C object variables are pointers types. The id type is predefined as a pointer type, so there's no need to add the asterisk.

Nested Messages(内部消息)

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, nested messages look like this:

方法2的结果将作为参数输入到方法1中。而在objective-c中,内部方法调用如下:

[NSString stringWithFormat:[prefs format]];

Avoid nested nesting more than two message calls on a single line, as it easily gets unreadable.

尽量避免在一行中循环嵌套调用超过2个方法,否则将很难阅读。

Multi-Input Methods

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

一些方法需要输入多个参数。在objective-c中,一个方法名被拆分成几部分。在header中,方法定义如下:

-(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.

并不仅仅通过方法名字区分,在系统运行时实际上存在的是writeToFile:atomically:

Accessors(访问器)

All instance variables are private in Objective-C by default, so you should use accessors to get and set values in most cases. There are two syntaxes. This is the traditional 1.x syntax:

在objective-c中所有的实例变量默认都是private的,所以你需要使用访问控制去get set变量。

[photo setCaption:@"Day at the Beach"];

output = [photo caption];

The code on the second line is not reading the instance variable directly. It's actually calling a method named caption. In most cases, you don't add the "get" prefix to getters in Objective-C. 
在上面第二行代码中不是直接读取变量。实际上是调用了一个名字为caption的方法。通常情况下你使用getter的时候无需添加get在变量前。无论你如何理解方括号里面的内容,都是调用了一个对象或类的方法。
Whenever you see code inside square brackets, you are sending a message to an object or a class.

Dot Syntax

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

作为mac os x10.5的一部分,新的objective-c2.0中有了点存取语法,如:

photo.caption = @"Day at the Beach";

output = photo.caption;

You can use either style, but choose only one for each project. The dot syntax should only be used setters and getters, not for general purpose methods.

你可以使用其中任何一种风格,但最好只选一种。

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 an autoreleased object, 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 and instantiates an object. 
通过了一个内部方法的调用。首先是调用NSString本身的alloc方法,该方法时底层用于开辟内存和实例化对象用的。
The second piece is a call to init on the new object. The init implementation usually does basic setup, such as creating instance variables. The details of that are unknown to you as a client of the class. 
第二是用新生成的object调用了init方法。Init常用于基本的初始化,比如创建一些常量。有些情况下,你可以使用不同的init进行初始化。
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 enable garbage collection. In general, this means that you don't have to think about memory management until you get to more complex cases. 
如果你在写mac os x应用,你就应该选择实现垃圾回收。通常情况下,如果你开发一个要求不高的应用时,无需自行考虑内存管理。然而,你并不会总在一个支持垃圾回收的应用开发环境下工作。有些情况下,你必须理解基本的内存管理。
However, you may not always be working with an environment that supports garbage collection. In that case, you need to know a few basic concepts.

If you create an object using the manual alloc style, you need to releasethe object later. You should not manually release an autoreleased object because your application will crash if you do. 
如果你使用alloc创建了一个对象,你就需要在后面自行release掉它。你不能够手动release掉一个声明为autoreleased的对象,否则你的应用将会崩溃。
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 the end of the current function.

There's more to learn about memory management, but it will make more sense after we 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 in two parts. 
创建一个类是比较简单的。通常需要两步。一个是使用.h文件存放变量和公有方法。使用.m文件实现这些公有方法。也用来定义一些private内部方法。
The class interface is usually stored in the ClassName.hfile, and defines instance variables and public methods.

The implementation is in the ClassName.m file and contains the actual code for these methods. It also often defines private methods that aren't available to clients of the class. 
下面是一个photo的接口.h
Here's what an interface file looks like. The class is called Photo, so the file is named Photo.h:

#import <Cocoa/Cocoa.h>

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

@end

First, 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 file multiple times. 
首先,我们导入了cocoa.h。该文件声明了一个photo类,继承自NSObject类型。定义了两个变量caption和photographer。最后,我们使用@end结束声明。
The @interface says that this is a declaration of the class Photo. The colon specifies the superclass, which is NSObject.

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

Finally, the @end symbol ends the class declaration.

Add Methods

Let's add some getters for the instance variables:

让我们先为变量添加getter和setter方法:

#import <Cocoa/Cocoa.h>

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

- caption;

- photographer;

@end

Remember, Objective-C methods typically leave out the "get" prefix. A single dash before a method name means it's a instance method. A plus before a method name means 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 <Cocoa/Cocoa.h>

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

- (NSString*) caption;

- (NSString*) photographer;

@end

Now let's add setters:

#import <Cocoa/Cocoa.h>

@interface Photo : NSObject {

NSString* caption;

NSString* photographer;

}

- (NSString*) caption;

- (NSString*) photographer;

- (void) setCaption: (NSString*)input;

- (void) setPhotographer: (NSString*)input;

@end

Setters don't need to return a value, so we just specify them as void.

Class Implementation

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

让我们来实现方法:

#import "Photo.h"

@implementation Photo

- (NSString*) caption {

return caption;

}

- (NSString*) photographer {

return photographer;

}

@end

This 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 statements.

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

- (void) setCaption: (NSString*)input

{

[caption autorelease];

caption = [input retain];

}

- (void) setPhotographer: (NSString*)input

{

[photographer autorelease];

photographer = [input retain];

}

Each setter deals with two variables. The first is a reference to the existing object, and the second is the new input object. In a garbage collected environment, 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, and retain 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. The autorelease method will release it sometime soon, but it will definitely stay around until the end of the current function (unless you add custom code to specifically change this).

The autorelease method is safer inside a setter because the variables for the new and old values could point to the same object. You wouldn't want to immediately release 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:

重写init方法:

- (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 to set 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 instance variables:

重写dealloc方法

- (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, the object 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 the finalize method.

More on Memory Management(更多的内存管理)

Objective-C's memory management system is called reference counting. All you have to do is keep track of your references, and the runtime does the actual freeing of memory. 
objective-c的内存管理使用的是引用计数。你必须维护你的引用栈,并在运行时自行释放内存。
In simplest terms, you alloc an object, maybe retain it at some point, then send one release for each alloc/retain you sent. So if you used alloc once and then retain once, you need to release twice.

比如说,你alloc了一个对象,或许也retain了他,然后你需要去release掉每一个你alloc/retain的对象。如果你使用alloc和retain各一次,那你必须release2次。

That's the theory of reference counting. But in practice, there are usually only two reasons to create an object: 
只有两种情况你需要去创建一个对象:

  1. 保证其是一个可用常量
  2. 在方法里单独使用
    1. To keep it as an instance variable
    2. To use temporarily for single use inside a function 

    In most cases, the setter for an instance variable should justautorelease the old object, and retain the new one. You then just make sure to release it in dealloc as well. 
    通常,setter一个变量的同时需要去autorelease一个旧对象,和retain新的对象。你需要保证在dealloc的时候释放它。
    So the only real work is managing local references inside a function. And there's only one rule: if you create an object with alloc or copy, send it a release or autorelease message at the end of the function. If you create an object any other way, do nothing.

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

- (void) setTotalAmount: (NSNumber*)input

{

[totalAmount autorelease];

totalAmount = [input retain];

}

- (void) dealloc

{

[totalAmount release];

[super dealloc];

}

Here's the other case, local references. We only need to release the object created 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 instance variable:

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't need to think about how the setters are implemented.

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