Objective-C 初学者指南

Translations: English | Chinese | Korean

Outline

目录

 

·        Getting Started

·        开始

o   Downloading this tutorial

o   下载该教程

      • All the source code for this beginners guide including makefiles is available by downloadingobjc.tar.gz. Many of the examples in this tutorial were written by Steve Kochan in the bookProgramming in Objective-C. If you want more detailed information and examples, feel free to check out his book. The examples on this site were used with his permission, so please don't copy them.
      • 该初学者教程中的所有源码,包括makefile文件都可以在这里进行下载:objc.tar.gz。本教程中的很多示例程序都是源自于Steve Kochan编写的Programming in Objective-C。如果你想获取更多详细的信息以及更多的示例程序,可以参见该书中的内容。本网站中使用的示例程序都是经过Steve Kochan本人允许的,所以请不要随便拷贝这些程序。

o   Setting up the environment

o   搭建环境

      • Linux/FreeBSD: Install GNUStep
      • Linux/FreeBSD系统:安装GNUStep
        1. In order to build GNUstep applications one must first execute the GNUstep.sh file in /usr/GNUstep/System/Makefiles/GNUstep.sh. This path depends on your system. Some put it in /usr, some /usr/lib, some /usr/local. If your shell is a csh/tcsh based shell, you'll want to execute GNUStep.csh instead. It's recommended that you put this script in your .bashrc or .cshrc.
        2. 我们必须先执行/usr/GNUstep/System/Makefiles/GNUstep.sh这个文件,以便能够构建GNUstep应用程序。该文件的路径取决于您所使用的系统。一些系统将上面的路径放置在/usr/lib目录下,一些则放置在/usr/local目录下。如果你系统中的shell是从C语言衍生而来的,那么您需要执行的是GUNStep.csh。我们建议您将这个脚本文件放置在.bashrc或者.cshrc目录下。
      • Mac OS X: Install XCode
      • Mac OS X系统: 安装XCode
      • Windows NT 5.X: Install cygwin or mingw and then install GNUStep
      • Windows NT 5.X系统:安装cygwin 或者 mingw 然后再安装 GNUStep

o   Preamble

o   序

      • This tutorial assumes you have some basic C knowledge, including C data types, what a function is, what a return value is, knowledge of pointers and basic memory management in C. If you haven't gotten this far, I highly suggest you pick up K and R's book,The C Programming Language. This is the book on C written by the writers of C.
      • 我们假设您已经有一定的C语言基础,包括C语言中的数据类型,什么是函数,什么是返回值以及指针和基本的内存管理的知识。如果您还不完全具备这些知识,我们强烈建议您先阅读由Brain Kernighan和Dennis Ritchie编写的《The C Programming Language》(C语言)这本书。其中Dennis Ritchie是C语言的发明者。
      • Objective-C, being a C derivative, inherits all of C's features. There are a few exceptions but they don't really deviate from what C offers as a language.
      • Objective-C是从C语言发展而来的。它继承了C的全部特性,并增加了少量特性。但是增加的这些特性并不影响从C语言继承的东西。
      • nil: In C/C++ you're probably used to NULL. In Objective-C it is nil. The difference is you can pass messages to nil (such as [nil message];) and this is perfectly legal. You cannot however do this with NULL.
      • nil(空):在C/C++中我们使用NULL来表示空。在Objective-C中,我们使用nil。其区别就是我们可以给空(nil)发送消息(例如,[nil message])并且这是完全合法的。然而对于NULL,我们是不能这样做的。
      • BOOL: C doesn't have an official boolean type, and in reality neither does Objective-C. It's however built into the Foundation classes (Namely from importing NSObject.h). nil is also included in this header file. BOOL in Objective-C has two modes, YES and NO rather than TRUE and FALSE.
      • 布尔:C语言中没有官方定义的布尔类型,实际上Objective-C中也是没有布尔类型的。然而,布尔类型被构建在了基础框架类中,也就是从NSObject.h中引入的。nil也是被包含在该头文件中的。Objective-C中的布尔类型的取值是YES或者NO,而不是TRUE或者FALSE。
      • #import vs #include: As you will notice in the hello world example, #import was used. #import is supported by the gcc compiler, however it is deprecated in favor of #include. #import is basically the same thing as #ifndef #define #endif at the top and bottom of every .h file you make. I find this to be retarded, as many other programmers will most likely agree. For all purposes, just use #import. It's less hassle, and if gcc ever does remove it chances are enough Objective-C developers exist to either keep it from getting removed or getting added back in. As an aside, Apple officially uses #import in all their code so if this ever did happen, you can be certain that Apple would conviently ship a forked version of gcc to add this back in.
      • 使用#import还是#include来进行引入呢?后续我们会发现,在hello world示例程序中我们使用#import进行引入。gcc编译器是支持#import的。然而,使用#import进行引入已经不再被提倡了,人们更喜欢使用#include。#import实际上和我们在每个.h头文件的头部和尾部使用的#ifdef #define #endif是相同的。我个人感觉这点看起来很弱智,很多程序员可能都会同意这点。在实际中,我们都使用#import来进行引入,关于这点争议较少。即使gcc确实不打算支持#import了,众多的Objective-C开发人员也会阻止这样事情的发生或者把对#import的支持增加进去。此外,苹果公司官方地在自己的代码中也是用#import来进行引入,因此,如果gcc果真不支持#import了,我们也可以确定苹果公司会提供支持使用#import进行引入的gcc的分支版本。
      • The word method and message are used interchangably in Objective-C, although messages have special properties. A message can be dynamically forwarded to another object. Calling a message on an object in Objective-C doesn't mean that the object implements that message, just that it knows how to respond to it somehow via directly implementing it or forwarding the message to an object that does know how to.
      • 在Objective-C中,我们会经常交替使用方法和消息这两个词汇,尽管消息和方法相比有一些特殊性。消息是可以被动态地传递给另外的对象。而调用一个对象的方法在Objective-C中并不意味着该对象就实现了对应的消息,只要该对象能知道该如何响应该消息即可。也许这种响应是通过直接实现具体操作来完成,也许只是简单地把消息转发给能处理该消息的别的对象。

o   Making hello world

o   编写hello world程序

      • hello.m
      • hello.m源文件

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      printf( "hello world\n" );

§      return 0;

§  }

      • output
      • 程序输出

hello world

      • You use #import instead of #include in Objective-C
      • 在Objective-C中,我们使用#import而不是#include来进行引入
      • The default file extention for Objective-C is .m
      • Objective-C程序文件的缺省扩展为.m

·        Creating classes

·        创建类

o   @interface

o   定义类使用关键字interface,interface直译为接口

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)这本书中的示例程序,经授权使用。
      • Fraction.h
      • 声明Fraction类的头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Fraction: NSObject {

§      int numerator;

§      int denominator;

§  }

§   

§  -(void) print;

§  -(void) setNumerator: (int) n;

§  -(void) setDenominator: (int) d;

§  -(int) numerator;

§  -(int) denominator;

§  @end

      • NSObject: Short for NeXTStep Object. Although this is less meaningful today since it's really OpenStep.
      • NSObject是NeXTStep对象的缩写。这点现如今已经不是特别重要了。因为他完全是OpenStep的。(译者注:更多关于OpenStep的信息可以在wikipedia检索到)
      • Inheritance is specified as Class: Parent, as seen with Fraction: NSObject.
      • 继承关系的表达:类名:基类名;正如上面的:Fraction:NSObject.
      • Instance variables go between @interface Class: Parent { .... }
      • 类的实例变量写在@interface Class: Parent { .... }中的大括号之间。
      • No access is set (protected, public, private). Default is protected. Setting the access will be shown later
      • 上述代码中没有指明访问权限(protected, public或者private).缺省情况下为protected。我们将在后面讲述如何进行权限设置。
      • Instance methods follow after the member variables. The format is: scope (returnType) methodName: (parameter1Type) parameter1Name;
      • 实例方法写在成员变量的括号之后。格式为:范围(返回值类型) 方法名称:(参数1的类型)参数1;
        1. scope refers to class or instance. instance methods begin with - class level methods begin with+
        2. 其中范围指的是该方式为类的方法还是实例的方法。实例方法以-开始;类得方法以+开始。
      • Interface ends with @end
      • 类的定义以@end结束

o   @implementation

o   类的实现

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)这本书中的示例程序,经授权使用。
      • Fraction.m
      • Fraction类得实现文件

§  #import "Fraction.h"

§  #import <stdio.h>

§   

§  @implementation Fraction

§  -(void) print {

§      printf( "%i/%i", numerator, denominator );

§  }

§   

§  -(void) setNumerator: (int) n {

§      numerator = n;

§  }

§   

§  -(void) setDenominator: (int) d {

§      denominator = d;

§  }

§   

§  -(int) denominator {

§      return denominator;

§  }

§   

§  -(int) numerator {

§      return numerator;

§  }

§  @end

      • @implementation ClassName starts the implementation @end ends it
      • 类的实现以@implementation 类名 开始;以@end结束
      • All the defined methods are implemented very simlar to how they are declared in the interface
      • 所有类中定义的方法都以与声明时相似的方式加以实现

o   Piecing it together

o   类的定义与实现的结合

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)这本书中的示例程序,经授权使用。
      • main.m
      • 主程序文件

§  #import <stdio.h>

§  #import "Fraction.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //创建新的实例

§      Fraction *frac = [[Fraction alloc] init];

§   

§      // set the values

§      //设置对象的值

§      [frac setNumerator: 1];

§      [frac setDenominator: 3];

§   

§      // print it

§      //输出对象

§      printf( "The fraction is: " );

§      [frac print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [frac release];

§   

§      return 0;

§  }

      • output
      • 输出

The fraction is: 1/3

      • Fraction *frac = [[Fraction alloc] init];
      • 关于这一行:Fraction *frac = [[Fraction alloc] init];
        1. There are several important things in this one line.
        2. 这一行中有几点重要的知识。
        3. The way methods in Objective-C are called is [object method], which is similar to object->method() in C++
        4. Objective-C中的方法是通过[对象 方法]的方式来被调用的,这与C++中的 对象->方法 的形式有些类似。
        5. Objective-C doesn't have value types, so there is nothing similar to C++'s: Fraction frac; frac.print();. You always deal with objects as pointers in Objective-C.
        6. Objective-C中不存在值类型,因此不存在类似C++中的:Fraction frac; frac.pring();的写法。在Objective-C中,我们用到的总是指向对象的指针。
        7. What this line is really doing is two things: [Fraction alloc] is calling the alloc method on the Fraction class. This is similar to mallocing memory, because that is all that is done in this operation.
        8. 这行代码真正做的是两件事情:[Fraction alloc]是调用Fraction类的alloc方法,仅完成对象空间的分配。这点类似于C++中的分配空间。
        9. [object init] is the constructor call, which initializes any variables in the object. This method is called on the instance returned from [Fraction alloc]. This operation is so common it's usually just done in one line as Object *var = [[Object alloc] init];
        10. [Object init]是调用构造函数,用来对对象中的变量进行初始化。这个方法是针对[Fracton alloc]返回的对象而调用的。这样的操作很普遍,因此通常被写在一行里面:Object *var = [[Object alloc] init];
      • [frac setNumerator: 1] is quite simple. It's calling the setNumerator method on frac, and passing it the parameter 1.
      • [frac setNumerator: 1]这句比较简单,就是调用frac对象的setNumerator方法,传递的参数为1。
      • Like every c variant, there's a construct for freeing memory. This is done via release, which is inherited from NSObject. This method will be explainted in greater detail later.
      • 和C语言中的对象一样,每个类都有析构函数(译者注:原文描述可能有误:怀疑应该为destruct,而不是construct)用来释放空间。Objective-C中是通过release完成的。release是从NSObject类继承而来的。我们将在后文中对该方法进行详细的描述。

·        The details...

·        更多细节⋯

o   Multiple Parameters

o   多个参数

      • Up until this point I haven't showed any way to specify multiple parameters. It's not as intuitive at first, but it's syntax is a welcome addition from Smalltalk
      • 到目前为止,我们还没有看到指定多个参数的示例。指定多个参数的语法是从Smalltalk语言来的。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)这本书中的示例程序,经授权使用。
      • Fraction.h
      • 声明Fraction类的头文件

§  ...

§  -(void) setNumerator: (int) n andDenominator: (int) d;

§  ...

      • Fraction.m
      • Fraction类的实现

§  ...

§  -(void) setNumerator: (int) n andDenominator: (int) d {

§      numerator = n;

§      denominator = d;

§  }

§  ...

      • main.m
      • 主程序文件

§  #import <stdio.h>

§  #import "Fraction.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //创建新的对象

§      Fraction *frac = [[Fraction alloc] init];

§      Fraction *frac2 = [[Fraction alloc] init];

§   

§      // set the values

§      //设置值

§      [frac setNumerator: 1];

§      [frac setDenominator: 3];

§   

§      // combined set

§      //一次设置对象的多个值

§      [frac2 setNumerator: 1 andDenominator: 5];

§   

§      // print it

§      //输出

§      printf( "The fraction is: " );

§      [frac print];

§      printf( "\n" );

§   

§      // print it

§      //输出

§      printf( "Fraction 2 is: " );

§      [frac2 print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [frac release];

§      [frac2 release];

§   

§      return 0;

§  }

      • output
      • 输出结果:

§  The fraction is: 1/3

§  Fraction 2 is: 1/5

      • The method is actually called setNumerator:andDenominator:
      • 其中用到的方法实际上是:setNumerator:andDenominator:
      • Additional parameters are added the same was as the 2nd, such that you'd have method:label1:label2:label3: and you'd call it with [obj method: param1 label1: param2 label2: param3 label3: param4]
      • 更多的参数是通过和上面第二个参数一样的方式来增加的。例如,我们可以有方法:标签1:标签2:标签3:,其调用的方式为:[对象 方法:参数1 标签1:参数2 标签2 标签2:参数3 标签3:参数4](译者注:上面编号很容易因为引起误会。由于参数1的标签通常都是作为方法名称的最后面的一个或者几个单词,因此在函数名称的冒号后面不需要与之对应的标签。这样以来,上述描述中的标签1实际上是参数2的描述;标签2实际上是对参数3的描述;以此类推。)
      • Labels are optional. It's possible to have a method named method:::. This is done by simply not specifing label names, but just a : to separate the parameters. This is however not advised.
      • 其中的标签是可选的。我们也可以指定方法的名称为:方法:::,也就是不指定标签,只使用:来分隔参数,但是建议不要使用这种方式。

o   Constructors

o   构造函数

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • Fraction.h
      • 声明Fraction类的头文件

§  ...

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d;

§  ...

      • Fraction.m
      • Fraction类的实现文件

§  ...

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d {

§      self = [super init];

§   

§      if ( self ) {

§          [self setNumerator: n andDenominator: d];

§      }

§   

§      return self;

§  }

§  ...

      • main.m
      • 主程序文件

§  #import <stdio.h>

§  #import "Fraction.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //创建新的对象

§      Fraction *frac = [[Fraction alloc] init];

§      Fraction *frac2 = [[Fraction alloc] init];

§      Fraction *frac3 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

§   

§      // set the values

§      //设置对象的值

§      [frac setNumerator: 1];

§      [frac setDenominator: 3];

§   

§      // combined set

§      //一次设置对象的多个值

§      [frac2 setNumerator: 1 andDenominator: 5];

§   

§      // print it

§      //输出

§      printf( "The fraction is: " );

§      [frac print];

§      printf( "\n" );

§   

§      printf( "Fraction 2 is: " );

§      [frac2 print];

§      printf( "\n" );

§   

§      printf( "Fraction 3 is: " );

§      [frac3 print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [frac release];

§      [frac2 release];

§      [frac3 release];

§   

§      return 0;

§  }

      • output
      • 输出

§  The fraction is: 1/3

§  Fraction 2 is: 1/5

§  Fraction 3 is: 3/10

      • @interface declaration is identical to a regular function
      • @interface头文件中的对构造函数的声明和一般的函数是一样的。
      • @implementation shows a new keyword: super
      • 在@implementation实现文件中出现了一个新的关键字:super
        1. Similar to Java, Objective-C only has one parent class.
        2. 和Java类似,在Objective-C中一个类只能有一个父类
        3. Accessing it's super constructor is done through [super init] and this is required for proper inheritance.
        4. 通过[super init]就可以访问父类的构造函数。这样做是必要的,是为了能够正确地实现继承关系。
        5. This returns an instance which you assign to another new keyword, self. Self is similar to this in Java and C++.
        6. 这个对父类构造函数调用的语句返回一个实例,我们把这个实例赋值给另外一个新的关键字self。Self关键字类似于Java或者C++中的this。
      • if ( self ) is the same as if ( self != nil ) to make sure that the super constructor successfully returned a new object. nil is Objective-C's form of NULL from C/C++. This is gotten from including NSObject.
      • if ( self )等同于if ( self != nil ),用来确保父类的构造函数成功地返回了一个对象。Objective-C中的nil相当于C/C++中的NULL,引入NSObject即可使用。
      • After you've initialized the varialbes, you return yourself with return self;
      • 在给变量进行了初始化之后,我们通过return self返回自身的对象。
      • The deafult constructor is -(id) init;
      • 缺省的构造函数为-(id) init;
      • Constructors in Objective-C are technically just "init" methods, they aren't a special construct like they are in C++ and Java.
      • 在Objective-C中构造函数从技术层面上来讲只是进行初始化工作的方法。这点不像在C++或者Java中是作为一个特殊的方法出现的。

o   Access Privledges

o   访问权限

      • The default access is @protected
      • 缺省的访问权限是@protected
      • Java implements this with public/private/protected modifiers infront of methods and variables. Objective-C's approach is much more similar to C++'s for instance variables
      • 在Java中是通过把限定符public/private/protected放置在方法或者变量的前面来进行限制的。Objective-C的方法则更类似于C++中的对实例变量的访问权限的限定。
      • Access.h
      • Access类声明的头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Access: NSObject {

§  @public

§      int publicVar;

§  @private

§      int privateVar;

§      int privateVar2;

§  @protected

§      int protectedVar;

§  }

§  @end

      • Access.m
      • Access的实现文件

§  #import "Access.h"

§   

§  @implementation Access

§  @end

      • main.m
      • 主程序

§  #import "Access.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      Access *a = [[Access alloc] init];

§   

§      // works

§      //下面的语句可以正常工作

§      a->publicVar = 5;

§      printf( "public var: %i\n", a->publicVar );

§   

§      // doesn't compile

§      //下面的语句编译是会报错

§      //a->privateVar = 10;

§      //printf( "private var: %i\n", a->privateVar );

§   

§      [a release];

§      return 0;

§  }

      • output
      • 输出

public var: 5

      • As you an see, instead of private: [list of vars] public: [list of vars] like in C++, it's just @private, @protected, etc.
      • 我们可以看出,我们不是完全使用C++中的 限定符:[变量列表]的方式来表明访问权限的;而是使用:@限定符的方式来进行访问权限的声明。

o   Class level access

o   类级别的访问权限

      • Often it's nice to have class level variables and functions, for instance when keeping track of the times an object has been instanciated.
      • 我们经常还需要类级别的变量和函数。例如,为了跟踪一个类被实例化的次数,我们就需要使用类级别的变量。
      • ClassA.h
      • 声明类ClassA的头文件

§  #import <Foundation/NSObject.h>

§   

§  static int count;

§   

§  @interface ClassA: NSObject

§  +(int) initCount;

§  +(void) initialize;

§  @end

      • ClassA.m
      • 类ClassA的实现文件

§  #import "ClassA.h"

§   

§  @implementation ClassA

§  -(id) init {

§      self = [super init];

§      count++;

§      return self;

§  }

§   

§  +(int) initCount {

§      return count;

§  }

§   

§  +(void) initialize {

§      count = 0;

§  }

§  @end

      • main.m
      • 主程序

§  #import "ClassA.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      ClassA *c1 = [[ClassA alloc] init];

§      ClassA *c2 = [[ClassA alloc] init];

§   

§      // print count

§      //输出count的值

§      printf( "ClassA count: %i\n", [ClassA initCount] );

§   

§      ClassA *c3 = [[ClassA alloc] init];

§   

§      // print count again

§      //再次输出count的值

§      printf( "ClassA count: %i\n", [ClassA initCount] );

§   

§      [c1 release];

§      [c2 release];

§      [c3 release];

§   

§      return 0;

§  }

      • output
      • 输出

§  ClassA count: 2

§  ClassA count: 3

      • static int count = 0; This is how the class variable is declared. This is not the ideal place for such a variable. A nicer solution would have been like Java's implementation of static class variables. However this works
      • static int count = 0; 这句就是声明类变量的。这句的位置虽然不是一个很好声明变量地方,但是至少这种方式是可以工作的。更好的解决方式也许应该是像Java中实现静态类变量的方式那样。
      • +(int) initCount; This is the actual method that returns the count. Notice the subtle difference. Instead of using a - infront of the type, a + is used. The + denotes a class level function.
      • +(int) initCount; 这个方法用来返回count的值。请注意这里由一个细微的变化:方法的前面使用的是+,而不是-。其中的+就表示这是一个类的函数。
      • Accessing the variable is no different than member variables, as seen by count++ in the constructor of ClassA.
      • 对于count变量的访问和其他类型的实例变量的方法方式没有什么不同。这点我们在ClassA的构造函数中count++这句就可以看出来。
      • The +(void) initialize method is called when Objective-C starts your program, and it's called for every class. This is a good place to initialize class level variables like our count.
      • 类方法+(void) initialize在Objective-C程序启动的时候就会被调用,而且每个类的这个方法都会被调用。这里是一个很好的可用于对类似诸如count这样的类变量进行初始化的地方。

o   Exceptions

o   异常

      • NOTE: Exception handling is only supported in Mac OS X 10.3
      • 注意:异常处理只有在Mac OS X 10.3上才支持。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • CupWarningException.h
      • 类CupWarningException的声明头文件

§  #import <Foundation/NSException.h>

§   

§  @interface CupWarningException: NSException

§  @end

      • CupWarningException.m
      • 类CupWarningException的实现文件

§  #import "CupWarningException.h"

§   

§  @implementation CupWarningException

§  @end

      • CupOverflowException.h
      • 类CupOverflowException的声明头文件

§  #import <Foundation/NSException.h>

§   

§  @interface CupOverflowException: NSException

§  @end

      • CupOverflowException.m
      • 类CupOverflowException的实现文件

§  #import "CupOverflowException.h"

§   

§  @implementation CupOverflowException

§  @end

      • Cup.h
      • 类Cup的声明头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Cup: NSObject {

§      int level;

§  }

§   

§  -(int) level;

§  -(void) setLevel: (int) l;

§  -(void) fill;

§  -(void) empty;

§  -(void) print;

§  @end

      • Cup.m
      • 类Cup的实现

§  #import "Cup.h"

§  #import "CupOverflowException.h"

§  #import "CupWarningException.h"

§  #import <Foundation/NSException.h>

§  #import <Foundation/NSString.h>

§   

§  @implementation Cup

§  -(id) init {

§      self = [super init];

§   

§      if ( self ) {

§          [self setLevel: 0];

§      }

§   

§      return self;

§  }

§   

§  -(int) level {

§      return level;

§  }

§   

§  -(void) setLevel: (int) l {

§      level = l;

§   

§      if ( level > 100 ) {

§          // throw overflow

§          //抛出上溢异常

§          NSException *e = [CupOverflowException

§              exceptionWithName: @"CupOverflowException"

§              reason: @"The level is above 100"

§              userInfo: nil];

§          @throw e;

§      } else if ( level >= 50 ) {

§          // throw warning

§          //抛出警告异常

§          NSException *e = [CupWarningException

§              exceptionWithName: @"CupWarningException"

§              reason: @"The level is above or at 50"

§              userInfo: nil];

§          @throw e;

§      } else if ( level < 0 ) {

§          // throw exception

§          //抛出下溢异常

§          NSException *e = [NSException

§              exceptionWithName: @"CupUnderflowException"

§              reason: @"The level is below 0"

§              userInfo: nil];

§          @throw e;

§      }

§  }

§   

§  -(void) fill {

§      [self setLevel: level + 10];

§  }

§   

§  -(void) empty {

§      [self setLevel: level - 10];

§  }

§   

§  -(void) print {

§      printf( "Cup level is: %i\n", level );

§  }

§  @end

      • main.m
      • 主程序

§  #import "Cup.h"

§  #import "CupOverflowException.h"

§  #import "CupWarningException.h"

§  #import <Foundation/NSString.h>

§  #import <Foundation/NSException.h>

§  #import <Foundation/NSAutoreleasePool.h>

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

§      Cup *cup = [[Cup alloc] init];

§      int i;

§   

§      // this will work

§      // 不抛出任何异常

§      for ( i = 0; i < 4; i++ ) {

§          [cup fill];

§          [cup print];

§      }

§   

§      // this will throw exceptions

§      //下面的代码将抛出异常

§      for ( i = 0; i < 7; i++ ) {

§          @try {

§              [cup fill];

§          } @catch ( CupWarningException *e ) {

§              printf( "%s: ", [[e name] cString] );

§          } @catch ( CupOverflowException *e ) {

§              printf( "%s: ", [[e name] cString] );

§          } @finally {

§              [cup print];

§          }

§      }

§   

§      // throw a generic exception

§      //捕获所有的异常

§      @try {

§          [cup setLevel: -1];

§      } @catch ( NSException *e ) {

§          printf( "%s: %s\n", [[e name] cString], [[e reason] cString] );

§      }

§   

§      // free memory 

§      //释放存储空间

§      [cup release];

§      [pool release];

§  }

      • output
      • 输出

§  Cup level is: 10

§  Cup level is: 20

§  Cup level is: 30

§  Cup level is: 40

§  CupWarningException: Cup level is: 50

§  CupWarningException: Cup level is: 60

§  CupWarningException: Cup level is: 70

§  CupWarningException: Cup level is: 80

§  CupWarningException: Cup level is: 90

§  CupWarningException: Cup level is: 100

§  CupOverflowException: Cup level is: 110

§  CupUnderflowException: The level is below 0

      • NSAutoreleasePool is a memory management class. Don't worry about what this does right now.
      • NSAutoreleasePool是一个用于内存管理的类。这个我们暂时不用关心。
      • Exceptions that are thrown don't have to extend NSException. You can just as easily use an id as well: @catch ( id e ) { ... }
      • 抛出的异常可以不用继承与NSException类。我们可以仅仅简单的使用@catch(id e)就可以了。
      • There is also a finally block, which behaves just like Java's. The contents of a finally block are guaranteed to be called.
      • 上述代码中还有一个finally代码块,这个和java中的类似。finally代码块中的代码不管是否有异常抛出,都是会被执行的。
      • The string as show in Cup.m, @"CupOverflowException", is a constant NSString object. The @ sign is used often in Objective-C to denote extentions to the language. A C string is just like C and C++, "String constant", and is of type char *.
      • 出现在Cup.m中的字符串@"CupOverflowException"是一个常量的NSString 对象。其中的@符号会经常出现在Objective-C中,表示是对语言的扩展。C/C++语言中的字符串是char*类型的,例如"String constant"

·        Inheritance, Polymorphism, and other OOP features

·        继承,多态和其他的面向对象的特性

o   The id type

o   id类型

      • Objective-C has a type called id, that acts in some ways like a void*, though it's meant strictly for objects. Objective-C differs from Java and C++ in that when you call a method on an object, it doesn't need to know the type. That method simply just has to exist. This is refered to as message pasing in Objective-C.
      • Objective-C中有一种id的类型,它用起来和void *有些相似。但是他只能用于对象。Objective-C和Java以及C++的一个区别在于:当我们调用一个对象的方法的时候,我们不需要知道对象的类型。只需要这个方法存在即可。这种机制在Objective-C中被称为消息传递。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • Fraction.h
      • 声明Fraction类的头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Fraction: NSObject {

§      int numerator;

§      int denominator;

§  }

§   

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d;

§  -(void) print;

§  -(void) setNumerator: (int) d;

§  -(void) setDenominator: (int) d;

§  -(void) setNumerator: (int) n andDenominator: (int) d;

§  -(int) numerator;

§  -(int) denominator;

§  @end

      • Fraction.m
      • Fraction类的实现

§  #import "Fraction.h"

§  #import <stdio.h>

§   

§  @implementation Fraction

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d {

§      self = [super init];

§   

§      if ( self ) {

§          [self setNumerator: n andDenominator: d];

§      }

§   

§      return self;

§  }

§   

§  -(void) print {

§      printf( "%i / %i", numerator, denominator );

§  }

§   

§  -(void) setNumerator: (int) n {

§      numerator = n;

§  }

§   

§  -(void) setDenominator: (int) d {

§      denominator = d;

§  }

§   

§  -(void) setNumerator: (int) n andDenominator: (int) d {

§      numerator = n;

§      denominator = d;

§  }

§   

§  -(int) denominator {

§      return denominator;

§  }

§   

§  -(int) numerator {

§      return numerator;

§  }

§  @end

      • Complex.h
      • 声明Complex类的头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Complex: NSObject {

§      double real;

§      double imaginary;

§  }

§   

§  -(Complex*) initWithReal: (double) r andImaginary: (double) i;

§  -(void) setReal: (double) r;

§  -(void) setImaginary: (double) i;

§  -(void) setReal: (double) r andImaginary: (double) i;

§  -(double) real;

§  -(double) imaginary;

§  -(void) print;

§  @end

      • Complex.m
      • Complex类的实现

§  #import "Complex.h"

§  #import <stdio.h>

§   

§  @implementation Complex

§  -(Complex*) initWithReal: (double) r andImaginary: (double) i {

§      self = [super init];

§   

§      if ( self ) {

§          [self setReal: r andImaginary: i];

§      }

§   

§      return self;

§  }

§   

§  -(void) setReal: (double) r {

§      real = r;

§  }

§   

§  -(void) setImaginary: (double) i {

§      imaginary = i;

§  }

§   

§  -(void) setReal: (double) r andImaginary: (double) i {

§      real = r;

§      imaginary = i;

§  }

§   

§  -(double) real {

§      return real;

§  }

§   

§  -(double) imaginary {

§      return imaginary;

§  }

§   

§  -(void) print {

§      printf( "%_f + %_fi", real, imaginary ); 

§  }

§  @end

      • main.m
      • 主程序

§  #import <stdio.h>

§  #import "Fraction.h"

§  #import "Complex.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //创建新对象

§      Fraction *frac = [[Fraction alloc] initWithNumerator: 1 denominator: 10];

§      Complex *comp = [[Complex alloc] initWithReal: 10 andImaginary: 15];

§      id number;

§   

§      // print fraction

§      //输出分数

§      number = frac;

§      printf( "The fraction is: " );

§      [number print];

§      printf( "\n" );

§   

§      // print complex

§      //输出复数

§      number = comp;

§      printf( "The complex number is: " );

§      [number print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [frac release];

§      [comp release];

§      

§      return 0;

§  }

      • output

§  The fraction is: 1 / 10

§  The complex number is: 10.000000 + 15.000000i

      • There are obvious benefits to this type of dynamic binding. You don't have to know the type of something to call a method on it. If the object responds to a message, it will invoke that method. Lots of nasty casting isn't involved in this either, such as in Java to call .intValue() on an integer object would involve casting first, then calling the method.
      • 这种动态类型绑定的方式有个明显的好处:调用一个对象的方法的时候不需要直到这个对象的类型。如果该对象能够响应该消息,则会调用对应的方法。这其中也不需要进行让人头痛的类型转换。而在Java中想要调用一个整型数对象的.intValue()方法的时候,则会先进行类型转换,然后才会调用这个方法。

o   Inheritance

o   继承

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • Rectangle.h
      • 声明Rectangle类的头文件

§  #import <Foundation/NSObject.h>

§   

§  @interface Rectangle: NSObject {

§      int width;

§      int height;

§  }

§   

§  -(Rectangle*) initWithWidth: (int) w height: (int) h;

§  -(void) setWidth: (int) w;

§  -(void) setHeight: (int) h;

§  -(void) setWidth: (int) w height: (int) h;

§  -(int) width;

§  -(int) height; 

§  -(void) print;

§  @end

      • Rectangle.m
      • Rectangle类的实现

§  #import "Rectangle.h"

§  #import <stdio.h>

§   

§  @implementation Rectangle

§  -(Rectangle*) initWithWidth: (int) w height: (int) h {

§      self = [super init];

§   

§      if ( self ) {

§          [self setWidth: w height: h];

§      }

§   

§      return self;

§  }

§   

§  -(void) setWidth: (int) w {

§      width = w;

§  }

§   

§  -(void) setHeight: (int) h {

§      height = h;

§  }

§   

§  -(void) setWidth: (int) w height: (int) h {

§      width = w;

§      height = h;

§  }

§   

§  -(int) width {

§      return width;

§  }

§   

§  -(int) height {

§      return  height;

§  }

§   

§  -(void) print {

§      printf( "width = %i, height = %i", width, height ); 

§  }

§  @end

      • Square.h
      • 声明Square类的头文件

§  #import "Rectangle.h"

§   

§  @interface Square: Rectangle

§  -(Square*) initWithSize: (int) s;

§  -(void) setSize: (int) s;

§  -(int) size;

§  @end

      • Square.m
      • Square类的实现

§  #import "Square.h"

§   

§  @implementation Square

§  -(Square*) initWithSize: (int) s {

§      self = [super init];

§   

§      if ( self ) {

§          [self setSize: s];

§      }

§   

§      return self;

§  }

§   

§  -(void) setSize: (int) s {

§      width = s;

§      height = s;

§  }

§   

§  -(int) size {

§      return width;

§  }

§   

§  -(void) setWidth: (int) w {

§      [self setSize: w];

§  }

§   

§  -(void) setHeight: (int) h {

§      [self setSize: h]; 

§  }

§  @end

      • main.m
      • 主程序

§  #import "Square.h"

§  #import "Rectangle.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20];

§      Square *sq = [[Square alloc] initWithSize: 15];

§   

§      // print rec

§      //输出rec的值

§      printf( "Rectangle: " );

§      [rec print];

§      printf( "\n" );

§   

§      printf( "Square: " );

§      //输出rec的值

§      [sq print];

§      printf( "\n" );

§   

§      // update square

§      //更新sq的值后在输出其值

§      [sq setWidth: 20];

§      printf( "Square after change: " );

§      [sq print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [rec release];

§      [sq release];

§      return 0;

§  }

      • output

§  Rectangle: width = 10, height = 20

§  Square: width = 15, height = 15

§  Square after change: width = 20, height = 20

      • Inheritance in Objective-C is similar to Java. When you extend your super class (of which you can only have one parent) you can override the methods of your super class by simply putting the new implementations in the child classes implementation. No fooling with virtual tables like C++.
      • Objective-C中的继承和Java中的类似。当继承基类的时候(子类只能继承一个基类),我们可以对基类中的方法进行重写,这只需要在子类的实现文件中重新实现这个函数即可。这不像C++中的虚表那样复杂。
      • One thing left out here that is worth nothing is what would happen if you attempted to call the constructor for rectangle like: Square *sq = [[Square alloc] initWithWidth: 10 height: 15]. The answer is it will throw a compile error. Since the return type of the rectangle constructor is Rectangle*, not Square* this would not work. In such a case if you want this to occur, that's what the id variable is good for. Just change the Rectangle* return type to id if you wish to use your parent's constructors in a subclass.
      • 这里还有一个小小的问题:那就是如果企图如下使用rectangle类得构造函数,会发生什么情况了?uare *sq = [[Square alloc] initWithWidth: 10 height: 15];其结果是编译器会报告错误。这是因为rectangle构造函数的返回值是Rectangle*而不是Square*。如果我们确实需要这样做,此时就可以使用id类型。我们只需要把Rectangle构造函数的返回值修改为id,就可以使用父类的构造函数来初始化子类了。(译者注:这样并没有什么明显的好处,或者到目前译者还没有遇到非要这么做不可的情况。)

o   Dynamic types

o   动态类型

      • There are several methods for working with dynamic types in Objective-C
      • 在Objective-C中有下面的这些方式是会用到动态类型的。
 

-(BOOL) isKindOfClass: classObj

is object a descendent or member of classObj

对象的是否是classObj类的实例或者classObj的子类的实例

-(BOOL) isMemberOfClass: classObj

is object a member of classObj

对象是否是classObj类的实例

-(BOOL) respondsToSelector: selector

does the object have a method named specifiec by the selector

对象是否有有selector指定的方法

+(BOOL) instancesRespondToSelector: selector

does an object created by this class have the ability to respond to the specified selector

有该类生成的对象是否有由selector指定的方法

-(id) performSelector: selector

invoke the specified selector on the object

调用对象的指定的方法

      • Every object inherited from NSObject has a class method that returns a class object. This is very similar to Java's getClass() method. This class object is used in the methods above.
      • NSObject类得子类的所有对象都有一个方法:class;用于返回一个class类对象。这个和Java中的getClass()类似。这个class类的对象就可用于上述的方法中。
      • Selectors are used to represent a message in Objective-C. The syntax for creating a selector is shown in the next example
      • Selector是用来代表Objective-C中的消息的。创建selector的语法我们将会在下面的示例程序中看到。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • main.m
      • 主程序

§  #import "Square.h"

§  #import "Rectangle.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      Rectangle *rec = [[Rectangle alloc] initWithWidth: 10 height: 20];

§      Square *sq = [[Square alloc] initWithSize: 15];

§   

§      // isMemberOfClass

§      // isMemberOfClass 使用示例

§   

§      // true 

§      if ( [sq isMemberOfClass: [Square class]] == YES ) {

§          printf( "square is a member of square class\n" );

§      }

§   

§      // false

§      if ( [sq isMemberOfClass: [Rectangle class]] == YES ) {

§          printf( "square is a member of rectangle class\n" );

§      }

§   

§      // false

§      if ( [sq isMemberOfClass: [NSObject class]] == YES ) {

§          printf( "square is a member of object class\n" );

§      }

§   

§      // isKindOfClass

§      // isKindOfClass使用示例

§   

§      // true 

§      if ( [sq isKindOfClass: [Square class]] == YES ) {

§          printf( "square is a kind of square class\n" );

§      }

§   

§      // true

§      if ( [sq isKindOfClass: [Rectangle class]] == YES ) {

§          printf( "square is a kind of rectangle class\n" );

§      }

§   

§      // true

§      if ( [sq isKindOfClass: [NSObject class]] == YES ) {

§          printf( "square is a kind of object class\n" );

§      }

§   

§      // respondsToSelector

§      // respondsToSelector使用示例

§   

§      // true

§      if ( [sq respondsToSelector: @selector( setSize: )] == YES ) {

§          printf( "square responds to setSize: method\n" );

§      }

§   

§      // false

§      if ( [sq respondsToSelector: @selector( nonExistant )] == YES ) {

§          printf( "square responds to nonExistant method\n" );

§      }

§   

§      // true

§      if ( [Square respondsToSelector: @selector( alloc )] == YES ) {

§          printf( "square class responds to alloc method\n" );

§      }

§   

§      // instancesRespondToSelector

§      // instancesRespondToSelector使用示例

§   

§      // false

§      if ( [Rectangle instancesRespondToSelector: @selector( setSize: )] == YES ) {

§          printf( "rectangle instance responds to setSize: method\n" );

§      }

§   

§      // true

§      if ( [Square instancesRespondToSelector: @selector( setSize: )] == YES ) {

§          printf( "square instance responds to setSize: method\n" );

§      }

§   

§      // free memory

§      //释放存储空间

§      [rec release];

§      [sq release];

§   

§      return 0;

§  }

      • output
      • 输出

§  square is a member of square class

§  square is a kind of square class

§  square is a kind of rectangle class

§  square is a kind of object class

§  square responds to setSize: method

§  square class responds to alloc method

§  square instance responds to setSize: method

o   Categories

o   类别

      • When you want to add methods to a class, you typically extend it. However this solution isn't always perfect, especially if you want to rewrite the functionality of a class that you don't have the source code to. Categories allow you to add functionality to already existing classes without extending them. Ruby also has similar functionality to this.
      • 当我们需要为一个类增加方法的时候,通常我们只需要继承这个类,然后在子类中增加方法即可。然而,这种方式并不是总能奏效的,特别是当我们没有该类的源代码,而需要重新编写该类的某个函数的时候。类别这种技术就允许我们对已经存在的类不用继承也可以为其增加功能。Ruby也有类似的功能。(译者注:至于为什么要把这种机制称为类别,可能是由于在实际中大多是把需要增加的方法根据某种标准进行分类,相同类型的函数被放置在一起。因此就形成了不同类别的函数族的缘故吧。)
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • FractionMath.h
      • 声明FractionMath的头文件

§  #import "Fraction.h"

§   

§  @interface Fraction (Math)

§  -(Fraction*) add: (Fraction*) f;

§  -(Fraction*) mul: (Fraction*) f;

§  -(Fraction*) div: (Fraction*) f;

§  -(Fraction*) sub: (Fraction*) f;

§  @end

      • FractionMath.m
      • FractionMath类的实现

§  #import "FractionMath.h"

§   

§  @implementation Fraction (Math)

§  -(Fraction*) add: (Fraction*) f {

§      return [[Fraction alloc] initWithNumerator: numerator * [f denominator] +

§                                                  denominator * [f numerator]

§                               denominator: denominator * [f denominator]];

§  }

§   

§  -(Fraction*) mul: (Fraction*) f {

§      return [[Fraction alloc] initWithNumerator: numerator * [f numerator]

§                               denominator: denominator * [f denominator]];

§   

§  }

§   

§  -(Fraction*) div: (Fraction*) f {

§      return [[Fraction alloc] initWithNumerator: numerator * [f denominator]

§                               denominator: denominator * [f numerator]];

§  }

§   

§  -(Fraction*) sub: (Fraction*) f {

§      return [[Fraction alloc] initWithNumerator: numerator * [f denominator] -

§                                                  denominator * [f numerator]

§                               denominator: denominator * [f denominator]];

§  }@end

      • main.m
      • 主程序

§  #import <stdio.h>

§  #import "Fraction.h"

§  #import "FractionMath.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //创建新的对象

§      Fraction *frac1 = [[Fraction alloc] initWithNumerator: 1 denominator: 3];

§      Fraction *frac2 = [[Fraction alloc] initWithNumerator: 2 denominator: 5];

§      Fraction *frac3 = [frac1 mul: frac2];

§   

§      // print it

§      //输出这些对象的值

§      [frac1 print];

§      printf( " * " );

§      [frac2 print];

§      printf( " = " );

§      [frac3 print];

§      printf( "\n" );

§   

§      // free memory

§      //释放存储空间

§      [frac1 release];

§      [frac2 release];

§      [frac3 release];

§   

§      return 0;

§  }

      • output

§  1/3 * 2/5 = 2/15

      • The magic here is the two @implementation and @interface lines: @interface Fraction (Math) and @implementation Fraction (Math).
      • 其中最神奇的就是这两行:@interface Fraction (Math) and @implementation Fraction (Math)。
      • There can only be one category with the same name. Additional cateogies may be added on with different but unqiue names.
      • 类别的名字是唯一的,也就是说一个类中不能出现两个名称相同的类别。我们可以为一个类增加多个类别,但是这些类别的名称必须确保是唯一的。
      • Categories can't add instance variables.
      • 类别这种机制不能为类增加实例变量。
      • Categories are useful for creating private methods. Since Objective-C has no notion of private/protected/public methods like java does, one has to create categories that hide such functionality. The way this is done is by moving the private methods from your class's header (.h) file to the implementation file (.m). The following is a very brief example of what I mean.
      • 类别这种机制为我们提供了一种创建私有函数的方法。Objective-C中不像java那样有private(私有的)/proetected(保护的)/public(共有的)方法的区分,但我们可以使用类别这种机制来对私有的功能进行隐藏。具体的做法就是把似有方法从声明类的头文件中删除,但是在类的实现文件中进行实现。下面的这个简短的代码就对这种做法进行了演示。
      • MyClass.h
      • 声明MyClass类

§  #import <Foundation/NSObject.h>

§   

§  @interface MyClass: NSObject

§  -(void) publicMethod;

§  @end

      • MyClass.m
      • 实现MyClass类

§  #import "MyClass.h"

§  #import <stdio.h>

§   

§  @implementation MyClass

§  -(void) publicMethod {

§      printf( "public method\n" );

§  }

§  @end

§   

§  // private methods

§  //是由的方法,使用了类别机制,类别名称为Private

§  @interface MyClass (Private)

§  -(void) privateMethod;

§  @end

§   

§  @implementation MyClass (Private)

§  -(void) privateMethod {

§      printf( "private method\n" );

§  }

§  @end

      • main.m
      • 主程序

§  #import "MyClass.h"

§   

§  int main( int argc, const char *argv[] ) {

§      MyClass *obj = [[MyClass alloc] init];

§   

§      // this compiles

§      //下面的这行代码能通过编译

§      [obj publicMethod];

§   

§      // this throws errors when compiling

§      //下面的这行代码将引发编译器报告错误

§      //[obj privateMethod];

§   

§      // free memory

§      //释放存储空间

§      [obj release];

§      return 0;

§  }

      • output

public method

o   Posing

o   伪装

      • Posing is similar to categories, but with a twist. It allows you to extend a class, and make your subclass pose (in place of) the super class globally. For instance: Say you have NSArrayChild that extends NSArray. If you made NSArrayChild pose for NSArray all your code would begin using the NSArrayChild instead of NSArray automatically.
      • 伪装和类别有一些相似,但是理解起来稍微复杂一些。伪装技术使得我们可以继承某个类并且让我们自己的子类伪装成基类,这种伪装是全局性的。例如,假设我们有自己的子类NSArrayChild,他是由NSArray继承而来的。如果我们让NSArrayChild伪装成NSArray,那么我们代码将自动使用NSArrayChild的方法而不是NSArray类的方法。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • FractionB.h
      • 声明FractionB类的头文件

§  #import "Fraction.h"

§   

§  @interface FractionB: Fraction

§  -(void) print;

§  @end

      • FractionB.m
      • FractionB类的实现

§  #import "FractionB.h"

§  #import <stdio.h>

§  @implementation FractionB

§  -(void) print {

§      printf( "(%i/%i)", numerator, denominator );

§  }

§  @end

      • main.m
      • 主程序

§  #import <stdio.h>

§  #import "Fraction.h"

§  #import "FractionB.h"

§   

§  int main( int argc, const char *argv[] ) {

§      Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

§   

§      // print it

§      //输出

§      printf( "The fraction is: " );

§      [frac print];

§      printf( "\n" );

§   

§      // make FractionB pose as Fraction

§      //使用FractionB替换Fraction类

§      [FractionB poseAsClass: [Fraction class]];

§   

§      Fraction *frac2 = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

§   

§      // print it

§      //重新输出

§      printf( "The fraction is: " );

§      [frac2 print];

§      printf( "\n" );

§   

§      // free memory

§      //是否存储空间

§      [frac release];

§      [frac2 release];

§   

§      return 0;

§  }

      • output

§  The fraction is: 3/10

§  The fraction is: (3/10)

      • The output from this program would print the first fraction s 3/10. The second would output (3/10), which is implemented by FractionB.
      • 上面程序运行时,先是输出3/10,然后输出由FractionB实现的 (3/10)。
      • The method poseAsClass is part of NSObject. This allows a subclass to pose as a superclass.
      • poseAsClass是NSObject类的方法。使用这个方法可以实现使用子类替换基类的功能(译者注:该方法在MAC OS X v10.5上已经废弃,不建议使用。)

o   Protocols

o   协议

      • A Protocol in Objective-C is identical in functionality to an interface in Java, or a purely virtual class in C++.
      • Objective-C中的协议与Java中接口是对等的,或者说与C++中的纯虚函数是对等的。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • Printing.h
      • 声明一个Pringting协议

§  @protocol Printing

§  -(void) print;

§  @end

      • Fraction.h
      • 声明Fraction类的头文件

§  #import <Foundation/NSObject.h>

§  #import "Printing.h"

§   

§  @interface Fraction: NSObject <Printing, NSCopying> {

§      int numerator;

§      int denominator;

§  }

§   

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d;

§  -(void) setNumerator: (int) d;

§  -(void) setDenominator: (int) d;

§  -(void) setNumerator: (int) n andDenominator: (int) d;

§  -(int) numerator;

§  -(int) denominator;

§  @end

      • Fraction.m
      • Fraction类的实现

§  #import "Fraction.h"

§  #import <stdio.h>

§   

§  @implementation Fraction

§  -(Fraction*) initWithNumerator: (int) n denominator: (int) d {

§      self = [super init];

§   

§      if ( self ) {

§          [self setNumerator: n andDenominator: d];

§      }

§   

§      return self;

§  }

§   

§  -(void) print {

§      printf( "%i/%i", numerator, denominator );

§  }

§   

§  -(void) setNumerator: (int) n {

§      numerator = n;

§  }

§   

§  -(void) setDenominator: (int) d {

§      denominator = d;

§  }

§   

§  -(void) setNumerator: (int) n andDenominator: (int) d {

§      numerator = n;

§      denominator = d;

§  }

§   

§  -(int) denominator {

§      return denominator;

§  }

§   

§  -(int) numerator {

§      return numerator;

§  }

§   

§  -(Fraction*) copyWithZone: (NSZone*) zone {

§      return [[Fraction allocWithZone: zone] initWithNumerator: numerator

§                                             denominator: denominator];

§  }

§  @end

      • Complex.h
      • 声明Complex类的头文件

§  #import <Foundation/NSObject.h>

§  #import "Printing.h"

§   

§  @interface Complex: NSObject <Printing> {

§      double real;

§      double imaginary;

§  }

§   

§  -(Complex*) initWithReal: (double) r andImaginary: (double) i;

§  -(void) setReal: (double) r;

§  -(void) setImaginary: (double) i;

§  -(void) setReal: (double) r andImaginary: (double) i;

§  -(double) real;

§  -(double) imaginary;

§  @end

      • Complex.m
      • Complex类的实现

§  #import "Complex.h"

§  #import <stdio.h>

§   

§  @implementation Complex

§  -(Complex*) initWithReal: (double) r andImaginary: (double) i {

§      self = [super init];

§   

§      if ( self ) {

§          [self setReal: r andImaginary: i];

§      }

§   

§      return self;

§  }

§   

§  -(void) setReal: (double) r {

§      real = r;

§  }

§   

§  -(void) setImaginary: (double) i {

§      imaginary = i;

§  }

§   

§  -(void) setReal: (double) r andImaginary: (double) i {

§      real = r;

§      imaginary = i;

§  }

§   

§  -(double) real {

§      return real;

§  }

§   

§  -(double) imaginary {

§      return imaginary;

§  }

§   

§  -(void) print {

§      printf( "%_f + %_fi", real, imaginary );

§  }

§  @end

      • main.m
      • 主程序

§  #import <stdio.h>

§  #import "Fraction.h"

§  #import "Complex.h"

§   

§  int main( int argc, const char *argv[] ) {

§      // create a new instance

§      //生成新的实例

§      Fraction *frac = [[Fraction alloc] initWithNumerator: 3 denominator: 10];

§      Complex *comp = [[Complex alloc] initWithReal: 5 andImaginary: 15];

§      id <Printing> printable;

§      id <NSCopying, Printing> copyPrintable;

§   

§      // print it

§      //输出分数

§      printable = frac;

§      printf( "The fraction is: " );

§      [printable print];

§      printf( "\n" );

§   

§      // print complex

§      //输出复数

§      printable = comp;

§      printf( "The complex number is: " );

§      [printable print];

§      printf( "\n" );

§   

§      // this compiles because Fraction comforms to both Printing and NSCopyable

§      //下面这句代码是正确的。因为frac的类型是Fraction,该类既遵从Pringting协议也遵从NSCopying

§      //(译者注:原文中描述为NSCopyable,错了。)协议。

§      copyPrintable = frac;

§   

§      // this doesn't compile because Complex only conforms to Printing

§      //下面的语句是错误的。因为Complex类只遵从Printing协议,而不遵从NSCopying协议

§      //copyPrintable = comp;

§   

§      // test conformance

§   

§      // true

§      if ( [frac conformsToProtocol: @protocol( NSCopying )] == YES ) {

§          printf( "Fraction conforms to NSCopying\n" );

§      }

§   

§      // false

§      if ( [comp conformsToProtocol: @protocol( NSCopying )] == YES ) {

§          printf( "Complex conforms to NSCopying\n" );

§      }

§   

§      // free memory

§      //释放存储空间

§      [frac release];

§      [comp release];

§      return 0;

§  }

      • output
      • 输出

§  The fraction is: 3/10

§  The complex number is: 5.000000 + 15.000000i

§  Fraction conforms to NSCopying

      • The protocol specification is quite simple. it is basically @protocol ProtocolName (methods you must implement) @end.
      • 对协议的详细描述的语法是很简单的:

@protocol 协议名称

必须实现的方法

@end.

      • To conform to a protocol, you put the protocols you're conforming to in <>'s, and comma separate them. Example: @interface SomeClass <Protocol1, Protocol2, Protocol3>
      • 如果某个类需要遵从某些协议,我们就把需要遵从的协议名称列举在类名称后面的尖括号中,用逗号隔开。例如:

@interface SomeClass <协议名称1, 协议名称2, 协议名称3>

      • The methods that the protocol requires to be implemented are not required to be in the list of methods for the header file. As you can see, Complex.h doesn't have a definition for -(void) print, but it still implements it since it conforms to the protocol.
      • 协议规定必须实现的方法可以不用出现在实现了该协议的类的头文件中。在上面的程序中,虽然Complex.h中并没有声明- (void) print方法,但是在实现文件中是必须要实现该方法的。
      • One unique aspect of Objective-C's interface system is how you specify types. Rather than specifying it like Java or C++ as: Printing *someVar = ( Printing * ) frac; for example, you use the id type with a restricted protocol: id <Printing> var = frac; This allows you to dynamically specify a type that requires multiple protocols, all with one variable. Such as: id <Printing, NSCopying> var = frac;
      • Objective-C中关于协议的一个特殊的地方在于如何指定对象的类型。和Java或者C++中采用如下的写法:Printing * someVar = (Printing *)frac不同,我们使用id<协议名> 变量名 = frac;的方法。这种写法使得我们可以动态地声明一个实现了多个协议的变量。例如 id<Printing, NSCopying> 变量名 = frac;
      • Much like using @selector for testing an object's inheritance, you can use @protocol to test for conformance of interfaces. [object conformsToProtocol: @protocol( SomeProtocol )] returns a BOOL if the object conforms to that protocol. This works the same for classes as well: [SomeClass conformsToProtocol: @protocol( SomeProtocol )].
      • 和我们可以使用@selector来检测一个对象是否是具有某种继承关系一样,我们也可以使用@protocol来检测某个对象是否遵从某个协议。[对象 conformsToProtocol: @protocol( 协议名 )]这个方法返回指定对象是否遵从指定的协议。这种写法也适用于类:[类名 conformsToProtocol:@protocol(协议名)]

·        Memory Management

·        存储空间管理

    • Up until now I've kind of dodged memory management in Objective-C. Sure you can call dealloc on an object, but what happens if the object contains pointers to other objects? One has to be concerned about freeing the memory of those objects as well. Also how does the Foundation framework manage memory when you create classes from it? This will all be explained.
    • 到目前为止,我们一直都在回避Objective-C中的存储空间管理的问题。我们当然是可以随时销毁(dealloc)一个对象的。但是如果对象中含有指向别的对象的指针,此时会发生什么情况呢?我们也必须关注如何释放这些对象的存储空间。另外,Ojective-C的基本框架在我们创建类的时候又是如何进行存储空间管理的呢?我们将在下面进行讨论。
    • Note: everything up until this point has been properly memory managed, incase you're wondering.
    • 到目前为止我们所写的程序都是正确地处理了存储空间问题的,这点不需要怀疑。

o   Retain and Release

o   持有和释放

      • Retain and release are two methods inherited from any object that has NSObject as a parent. Each object has an internal counter that can be used to keep track of the number references an object has. So if you have 3 referneces, you don't want to dealloc yourself. However once you reach 0, you should dealloc yourself. [object retain] increments the counter by 1 (which starts at 1) and [object release] decrements it by 1. If the [object release] invocation causes the count to reach 0, dealloc is then called.
      • 持有retain和释放release是任何从NSObject继承的子类对象都有的两个方法。每个对象都有一个内部的计数器,用来跟踪该对象的引用计数。如果一个对象的引用计数为3,显然这个对象不应该被销毁。但是一点该对象的引用计数变为0了,它就应该被销毁。[对象 retian]是用来把对象的引用计数增加1的(对象的引用计数是从1开始的);[对象 release]是用来把对象的引用计数减去1的。如果[对象 release]后,对象的引用计数为0了,那么系统会自动调用dealloc方法销毁该对象。
      • Fraction.m

§  ...

§  -(void) dealloc {

§      printf( "Deallocing fraction\n" );

§      [super dealloc];

§  }

§  ...

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • main.m

§  #import "Fraction.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      Fraction *frac1 = [[Fraction alloc] init];

§      Fraction *frac2 = [[Fraction alloc] init];

§   

§      // print current counts

§      //输出当前的引用计数

§      printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] );

§      printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] );

§   

§      // increment them

§      //增引用计数每次增加1

§      [frac1 retain]; // 2

§      [frac1 retain]; // 3

§      [frac2 retain]; // 2

§   

§      // print current counts

§      //输出当前的引用计数

§      printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] );

§      printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] );

§   

§      // decrement

§      //引用计数每次减少1

§      [frac1 release]; // 2

§      [frac2 release]; // 1

§   

§      // print current counts

§      //输出当前的引用计数

§      printf( "Fraction 1 retain count: %i\n", [frac1 retainCount] );

§      printf( "Fraction 2 retain count: %i\n", [frac2 retainCount] );

§   

§      // release them until they dealloc themselves

§      //继续释放对对象的引用,直到对象被自动销毁

§      [frac1 release]; // 1

§      [frac1 release]; // 0

§      [frac2 release]; // 0

§  }

      • output
      • 输出

§  Fraction 1 retain count: 1

§  Fraction 2 retain count: 1

§  Fraction 1 retain count: 3

§  Fraction 2 retain count: 2

§  Fraction 1 retain count: 2

§  Fraction 2 retain count: 1

§  Deallocing fraction

§  Deallocing fraction

      • The retain calls increment the counter. The release calls decrement it. One can get the count as an int by calling [obj retainCount]. Once the retainCount reaches 0, both objects dealloc themselves and you can see this when both print out "Deallocing fraction."
      • retain方法用来对对象的引用计数增加1;release方法用来对对象的引用计数减去1。我们可以通过[对象 retainCount]的方式来获取对象的引用计数。一旦对象的引用计数变为0了,程序中的两个对象的dealloc就会被调用,正如我们看到的输出“Deallocing fraction”那样

o   Dealloc

o   销毁对象

      • When your object contains other objects, you must free them whenever you yourself dealloc. One of the nice advantages to Objective-C is you can pass messages to nil, so there isn't a lot of error checking to release an object.
      • 如果我们的对象中包含有其他的对象,那我们就必须在该对象被销毁的时候对其他对象进行释放。Objective-C中比较好的一点就是可以给空对象(nil)发消息。因此在使用release的时候不需要过多的错误检测。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • AddressCard.h

§  #import <Foundation/NSObject.h>

§  #import <Foundation/NSString.h>

§   

§  @interface AddressCard: NSObject {

§      NSString *first;

§      NSString *last;

§      NSString *email;

§  }

§   

§  -(AddressCard*) initWithFirst: (NSString*) f

§                  last: (NSString*) l

§                  email: (NSString*) e;

§  -(NSString*) first;

§  -(NSString*) last;

§  -(NSString*) email;

§  -(void) setFirst: (NSString*) f;

§  -(void) setLast: (NSString*) l;

§  -(void) setEmail: (NSString*) e;

§  -(void) setFirst: (NSString*) f

§          last: (NSString*) l

§          email: (NSString*) e;

§  -(void) setFirst: (NSString*) f last: (NSString*) l;

§  -(void) print;

§  @end

      • AddressCard.m

§  #import "AddressCard.h"

§  #import <stdio.h>

§   

§  @implementation AddressCard

§  -(AddressCard*) initWithFirst: (NSString*) f

§                  last: (NSString*) l

§                  email: (NSString*) e {

§      self = [super init];

§   

§      if ( self ) {

§          [self setFirst: f last: l email: e];

§      }

§   

§      return self;

§  }

§   

§  -(NSString*) first {

§      return first;

§  }

§   

§  -(NSString*) last {

§      return last;

§  }

§   

§  -(NSString*) email {

§      return email;

§  }

§   

§  -(void) setFirst: (NSString*) f {

§      [f retain];

§      [first release];

§      first = f;

§  }

§   

§  -(void) setLast: (NSString*) l {

§      [l retain];

§      [last release];

§      last = l;

§  }

§   

§  -(void) setEmail: (NSString*) e {

§      [e retain];

§      [email release];

§      email = e;

§  }

§   

§  -(void) setFirst: (NSString*) f

§          last: (NSString*) l

§          email: (NSString*) e {

§      [self setFirst: f];

§      [self setLast: l];

§      [self setEmail: e];

§  }

§   

§  -(void) setFirst: (NSString*) f last: (NSString*) l {

§      [self setFirst: f];

§      [self setLast: l];

§  }

§   

§  -(void) print {

§      printf( "%s %s <%s>", [first cString],

§                                  [last cString],

§                                  [email cString] );

§  }

§   

§  -(void) dealloc {

§      [first release];

§      [last release];

§      [email release];

§   

§      [super dealloc];

§  }

§  @end

§   

      • main.m
      • 主程序

§  #import "AddressCard.h"

§  #import <Foundation/NSString.h>

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      NSString *first =[[NSString alloc] initWithCString: "Tom"];

§      NSString *last = [[NSString alloc] initWithCString: "Jones"];

§      NSString *email = [[NSString alloc] initWithCString: "[email protected]"];

§      AddressCard *tom = [[AddressCard alloc] initWithFirst: first

§                                              last: last

§                                              email: email];

§   

§      // we're done with the strings, so we must dealloc them

§      //对不再使用的字符串必须进行释放

§      [first release];

§      [last release];

§      [email release];

§   

§      // print to show the retain count

§      //输出对象的引用计数值

§      printf( "Retain count: %i\n", [[tom first] retainCount] );

§      [tom print];

§      printf( "\n" );

§   

§      // free memory

§      //释放对象的存储空间

§      [tom release];

§      return 0;

§  }

      • output
      • 输出

§  Retain count: 1

§  Tom Jones <[email protected]>

      • This example shows not only how to make a dealloc method, as shown in AddressCard.m, but one way to do member variables.
      • 上面的这个程序不仅给我们展示了应该如何编写dealloc方法,如AddressCard.m中所示,还给我们演示和处理成员变量的一种方法。
      • The order of the 3 operations in each set method is very important. Lets say you'r passing a parameter of yourself to one of your methods (a bit of an odd example, but this can happen). If you release first, THEN retain you will destruct yourself! That's why you should always 1) retain 2) release 3) set the value.
      • 上面程序中的设置函数(setter)中的3个操作的顺序非常重要。假设为函数传递的参数是一个自己的对象,此时如果我们先进行release操作,在进行retain操作,那么我们就等于先销毁了这个对象,然后在对一个销毁了的对象进行retain操作!这就是我们必须先retain,再release,最后在进行赋值操作的原因了。
      • Normally one wouldn't initialize variables with C strings because they don't support unicode. The next example, with NSAutoreleasePool shows the proper way to do strings and initializing.
      • This is just one way of handling member variable memory management. One way to handle this is to create copies inside your set methods.

o   Autorelease Pool

o   自动释放池

      • When you want to start doing more programming using NSString and other Foundation framework classes you need a more flexible system. This system is using Autorelease pools.
      • 当我们使用NSString类和其他的基本框架类进行更复杂的编程的时候,我们就需要使用到自动释放池了。自动释放池为我们提供了一个更灵活的系统。
      • When developing Mac Cocoa applications, the auto release pool is setup automatically for you.
      • 当我们在Mac系统下进行Cocoa 应用程序开发的时候,系统会自动地为我们建立自动释放池。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • main.m

§  #import <Foundation/NSString.h>

§  #import <Foundation/NSAutoreleasePool.h>

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

§      NSString *str1 = @"constant string";

§      NSString *str2 = [NSString stringWithString: @"string managed by the pool"];

§      NSString *str3 = [[NSString alloc] initWithString: @"self managed string"];

§   

§      // print the strings

§      //输出字符串

§      printf( "%s retain count: %x\n", [str1 cString], [str1 retainCount] );

§      printf( "%s retain count: %x\n", [str2 cString], [str2 retainCount] );

§      printf( "%s retain count: %x\n", [str3 cString], [str3 retainCount] );

§   

§      // free memory

§      //释放存储空间

§      [str3 release];

§   

§      // free pool

§      //释放自动释放池

§      [pool release];

§      return 0;

§  }

      • output
      • 输出

§  constant string retain count: ffffffff

§  string managed by the pool retain count: 1

§  self managed string retain count: 1

      • If you run this you'll notice a few things. One is that the retainCount of str1 is ffffffff.
      • 从上面程序的运行结果中我们看到一个很奇怪的结果:其中字符串str1的引用计数为ffffffff!
      • The other is, I only release str3, yet this program is memory management perfect. The reason is the first constant string is added to the autorelease pool automatically. The other string is made using stringWithString. This method creates a string that is owned by NSString class, which also puts it in the auto release pool.
      • 另外一点是我们只对str3进行了release操作。然而这个程序就存储空间管理这地点来讲是完全正确的。其原始就是因为:第一个常量字符串被自动放入到自动释放池中了;还有一个字符串是通过stringWithString方法生成的。这种方法创建的NSString类得对象也是被放入自动释放池的。
      • It's important to remember, for proper memory management, that convience methods like [NSString stringWithString: @"String"] use autorelease pools, but alloc methods like [[NSString alloc] initWithString: @"String"] do not use autorelease pools for managing memory.
      • 为了正确地进行存储空间的管理,我们必需明确非常重要的一点:类似于[NSString stringWithString:@ "String"]这种的便利写法使用到的是自动释放池;而通过类似于[[NSString alloc] initWithString: @"String"]这种使用alloc生成字符串的方法没有使用自动释放池,我们必需自己释放存储空间。
      • There are two ways to manage memory in Objective-C: 1) retain and release or 2) retain and release/autorelease.
      • 在Objective-C中有两种进行存储空间管理的方法:第一,retain和release;第二,retain和/release或者autorelease
      • For each retain, there must be one release OR one autorelease.
      • 一个retain必需有一个release或者一个autorelease与之对应。
      • The following example shows what I mean by this
      • 下面的代码演示了上面的描述的内容。
      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • Fraction.h
      • 声明Fraction类的头文件

§  ...

§  +(Fraction*) fractionWithNumerator: (int) n denominator: (int) d;

§  ...

      • Fraction.m
      • Fraction类的实现

§  ...

§  +(Fraction*) fractionWithNumerator: (int) n denominator: (int) d {

§      Fraction *ret = [[Fraction alloc] initWithNumerator: n denominator: d];

§      [ret autorelease];

§   

§      return ret;

§  }

§  ...

      • main.m
      • 主程序

§  #import <Foundation/NSAutoreleasePool.h>

§  #import "Fraction.h"

§  #import <stdio.h>

§   

§  int main( int argc, const char *argv[] ) {

§      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

§      Fraction *frac1 = [Fraction fractionWithNumerator: 2 denominator: 5];

§      Fraction *frac2 = [Fraction fractionWithNumerator: 1 denominator: 3];

§   

§      // print frac 1

§      //输出frac1

§      printf( "Fraction 1: " );

§      [frac1 print];

§      printf( "\n" );

§   

§      // print frac 2

§      //输出frac2

§      printf( "Fraction 2: " );

§      [frac2 print];

§      printf( "\n" );

§   

§      // this causes a segmentation fault

§      //下面的这句将导致和内存管理相关的错误:segmentation fault

§      //[frac1 release];

§   

§      // release the pool and all objects in it

§      //释放资源池和所有的对象

§      [pool release];

§      return 0;

§  }

      • output
      • 输出

§  Fraction 1: 2/5

§  Fraction 2: 1/3

      • In this example, the method is a class level method. After the object is created, autorelease is called on it. Inside the body of the main method, I never call release on the object.
      • 上面代码中Fraction类得唯一的方法是一个类方法。在创建了对象之后,调用了对象的autorelease方法。因此在main()方法中,我们不用调用该对象的release方法的。
      • The reason this works is because: for every retain, one release or autorelease must be called. The object's retain count starts out as 1, and I called autorelease on it once. This means 1 - 1 = 0. Once the autorelease pool is released, it counts the autorelease calls on all objects and decrements them with [obj release] with the same number of times autorelease was called per object.
      • 上述代码遵循了前面描述的每一个retain都必需有一个release或者autorelease与之配对的原则,因此能够正确的工作,不会出现存储空间相关的问题。生成对象的最初引用计数为1,后面有调用了该对象的autorelease一次,这意味着1-1=0。一旦自动释放池被释放的时候,系统会对每个对象的autorelease方法被调用的次数进行统计,并分别对这些对象做相同次数的release操作。
      • As the comment says, uncommenting that line causes a segment fault. Since autorelease was already called on the object, calling release on it, and then releasing the autorelease pool would attempt to call dealloc on an object that is nil, which is not valid. The end math is 1 (creation) - 1 (release) - 1 (autorelease) = -1.
      • 正如上面代码注释所描述的那样,[frac1 release];这句将导致和内存方法相关的一个错误:segmentation fault。这是因为之前我们已经调用过该对象的autorelease方法了,再调用release将导致自动释放池企图调用一个空对象(nil)的dealloc方法。这样做时非法的。引用计数的最终数值为:1(创建对象)-1(release) -1(autorelease) = -1。
      • Auto release pools can be dynamically created for large amounts of temporary objects. All one must do is create a pool, perform any large chunk of code that creates lots of temporary objects, then release the pool. As you may wonder, it this means it is possible to have more than one auto release pool at a time.
      • 在使用大量临时对象的时候,我们可以动态地生成自动释放池。我们所需要做的就是:先创建自动释放池,然后再代码中创建许多临时对象,最后释放自动释放池即可。以这种方法,我们还可以在同一时刻拥有多个自动释放池。

·        Foundation framework classes

·        基础框架类

    • The Foundation framework is similar to C++'s Standard Template Library. Although since Objective-C has real dynamic types, the horrible cludge that is C++'s templating is not necessary. This framework contains collections, networking, threading, and much more.
    • Objective-C中的基础框架类和C++中的标准模板库有些类似。尽管在Objective-C中有着真正的动态类型,但是其并没有C++模板那样复杂。基础框架类包含了:集合,网络,线程以及别的相关的类。

o   NSArray

o   数组类

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • main.m
      • 主程序

§  #import <Foundation/NSArray.h>

§  #import <Foundation/NSString.h>

§  #import <Foundation/NSAutoreleasePool.h>

§  #import <Foundation/NSEnumerator.h>

§  #import <stdio.h>

§   

§  void print( NSArray *array ) {

§      NSEnumerator *enumerator = [array objectEnumerator];

§      id obj;

§   

§      while ( obj = [enumerator nextObject] ) {

§          printf( "%s\n", [[obj description] cString] );

§      }

§  }

§   

§  int main( int argc, const char *argv[] ) {

§      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

§      NSArray *arr = [[NSArray alloc] initWithObjects:

§                      @"Me", @"Myself", @"I", nil];

§      NSMutableArray *mutable = [[NSMutableArray alloc] init];

§   

§      // enumerate over items

§      //遍历整个数组

§      printf( "----static array\n" );

§      print( arr );

§   

§      // add stuff

§      //为数组增加元素

§      [mutable addObject: @"One"];

§      [mutable addObject: @"Two"];

§      [mutable addObjectsFromArray: arr];

§      [mutable addObject: @"Three"];

§   

§      // print em

§      //输出mutable数组中的元素

§      printf( "----mutable array\n" );

§      print( mutable );

§   

§      // sort then print

§      //对mutable数组进行排序

§      printf( "----sorted mutable array\n" );

§      [mutable sortUsingSelector: @selector( caseInsensitiveCompare: )];

§      print( mutable );

§   

§      // free memory

§      //释放存储空间

§      [arr release];

§      [mutable release];

§      [pool release];

§   

§      return 0;

§  }

      • output
      • 输出

§  ----static array

§  Me

§  Myself

§  I

§  ----mutable array

§  One

§  Two

§  Me

§  Myself

§  I

§  Three

§  ----sorted mutable array

§  I

§  Me

§  Myself

§  One

§  Three

§  Two

      • There are two kinds of arrays (and of usually most data oriented Foundation classes) NSArray and NSMutableArray. As the name suggests, Mutable is changable, NSArray then is not. This means you can make an NSArray but once you have you can't change the length.
      • 有两种类型的数组NSArray和NSMutableArray。正如他们的名字那样,mutable就是可以改变的意思。NSArray数组是不可改变的。这就是说一旦创建了一个NSArray数组,就不能再改变其长度了。
      • You initialize an array via the constructor using Obj, Obj, Obj, ..., nil. The nil is an ending delimiter.
      • 我们可以使用构造函数来对一个数组进行初始化:对象1,对象2,对象3,...nil。其中的nil是结束的界定符。
      • The sorting shows how to sort an object using a selector. The selector tells the array to sort using NSString's case insensitive compare. If your object has several sort methods, you can choose anyone you want using this selector.
      • 上述程序中的排序为我们展示了如何使用selector来对数组进行排序。代码中的的selector是告诉编译器调用NSString类的区分大小写的比较函数来进行排序。如果我们自己数组中的对象支持多种排序方法,我们可以使用selector来指定需要的排序比较方法。
      • In the print method, I used the method description. This is similar to Java's toString. It returns an NSString representation of an object.
      • 在print方法中用到了description方法。这个方法和Java中的toString方法很类似。它返回的是一个代表该对象的一个NSString对象。
      • NSEnumerator is similar to Java's enumerator system. The reason why while ( obj = [array objectEnumerator] ) works is because objectEnumerator returns nil on the last object. Since in C nil is usually 0, this is the same as false. ( ( obj = [array objectEnumerator] ) != nil ) might be preferable(译者注:标记为红色的这段原文描述与程序不符,应该是错误的。以下为对纠正后译文。)
      • NSEnumerator和java中的迭代器系统是类似的。objectEnumerator方法返回的是一个迭代器,方便我们对数组中的元素进行遍历。迭代器的nextObject方法返回的是集合对象中的下一个元素;如果所有的元素都已经被遍历过了,则返回nil。这也是为什么while ( obj = [enumerator nextObject] )这么写的原因了。在C语言中NULL的值为0, 因此这种写法和C中的((obj = [enumerator nextObject]) != nil )有着相同的意思。

o   NSDictionary

      • Based on an example in "Programming in Objective-C," Copyright © 2004 by Sams Publishing. Used with permission
      • 下面的程序段是基于《Programming in Objective-C》(Objective-C 编程) (版权所有 © 2004)中的示例程序,经授权使用。
      • main.m

§  #import <Foundation/NSString.h>

§  #import <Foundation/NSAutoreleasePool.h>

§  #import <Foundation/NSDictionary.h>

§  #import <Foundation/NSEnumerator.h>

§  #import <Foundation/Foundation.h<

§  #import <stdio.h>

§   

§  void print( NSDictionary *map ) {

§      NSEnumerator *enumerator = [map keyEnumerator];

§      id key;

§   

§      while ( key = [enumerator nextObject] ) {

§          printf( "%s => %s\n",

§                  [[key description] cString],

§                  [[[map objectForKey: key] description] cString] );

§      }

§  }

§   

§  int main( int argc, const char *argv[] ) {

§      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

§      NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:

§          @"one", [NSNumber numberWithInt: 1],

§          @"two", [NSNumber numberWithInt: 2],

§          @"three", [NSNumber numberWithInt: 3],

§          nil];

§      NSMutableDictionary *mutable = [[NSMutableDictionary alloc] init];

§   

§      // print dictionary

§      //输出字典的内容

§      printf( "----static dictionary\n" );

§      print( dictionary );

§   

§      // add objects

§      //给字典中增加条目

§      [mutable setObject: @"Tom" forKey: @"[email protected]"];

§      [mutable setObject: @"Bob" forKey: @"[email protected]" ];

§   

§      // print mutable dictionary

§      //输出可修改的字典

§      printf( "----mutable dictionary\n" );

§      print( mutable );

§   

§      // free memory 

§      //释放存储空间

§      [dictionary release];

§      [mutable release];

§      [pool release];

§      return 0;

§  }

      • output
      • 输出

§  ----static dictionary

§  1 => one

§  2 => two

§  3 => three

§  ----mutable dictionary

§  [email protected] => Bob

§  [email protected] => Tom

·        Pros and Cons

·        与其他语言相比的优缺点

o   Pros

o   优点

      • Cateogies
      • 类别机制
      • Posing
      • 伪装机制
      • Dynamic typing
      • 动态类型
      • Pointer counting
      • 指针的引用计数
      • Flexible message passing
      • 灵活的消息传递机制
      • Not an overly complex extention to C
      • 对C语言的进行了合理有度的扩充
      • Can interface with C++ via Objective-C++
      • 通过Objective-C++可以和C++交互

o   Cons

o   缺点

      • No namespaces
      • 没有命名空间
      • No operator overloading (this is often considered a Pro though, but operator overloading usedproperly can reduce code clutter)
      • 不支持运算符重载(这点通常也被认为是优点。但是合理地使用运算符重载确实可以降低代码的复杂度)
      • Still some cruft in language, although no more than C++
      • 语言中还有一些需要修整的地方,但是和C++相比并不算多。

·        More Information

·        更多信息

 

Last modified: April 13, 2004. 翻译:[email protected]

猜你喜欢

转载自blog.csdn.net/kkxmforever/article/details/39252769