Objective-C 苹果开发文档--02 Defining Classes

Defining Classes

当您为OS X或iOS编写软件的时候,大部分时间使用对象。objective - c中的对象就像其他面向对象编程语言中的对象:他们把相关的数据与行为打包。

一个应用程序作为一个大型的生态系统,系统中的对象是相互关联的,彼此进行通信,以解决具体问题,如显示一个可视化界面,对用户输入,或存储信息。在OS X或iOS开发中,您不需要从头开始创建对象来解决所有的问题,相反,你有一个很大的类库供你使用,由Cocoa (for OS X) 和 Cocoa Touch (for iOS)提供

这些对象中有可以立即使用的,比如字符串和数字等基本数据类型,或用户界面元素(如按钮和表视图)。一些是专为当您定制自己的代码时,以你需要的方式使用的。软件开发过程涉及如何把底层框架提供的对象和自己的对象更好地定制以及结合在一起的决定,以便给你的应用独特的特性和功能。

在面向对象的编程术语中,一个对象是一个类的实例。本章演示了在objective - c中,通过声明一个接口如何定义一个类,用来描述你打算使用的类及其实例。这个接口包含类可以接收消息的列表,所以你还需要提供类的实现,其中包含要执行的代码以响应每个消息。


Classes Are Blueprints for Objects

一个类描述了任何特定类型的对象的常见行为和属性。对于一个字符串对象(在objective - c,这是类NSString的一个实例),该类提供了各种方法来检查和转换内部的字符。同样,NSNumber类用于描述一些数值对象,提供一些围绕数值类型对象的功能,比如将该值转换为别的数字类型的值。

以同样的方式,多个建筑由相同的蓝图构建,在结构上就是是相同的,每一个类的实例共享相同的属性和行为作为该类的所有其他实例。每个NSString实例表现的是一样的,无论它内部字符串的字符是什么。

任何特定的对象都是要设计被用于在特定的方面。你可能知道一个字符串对象表示一些字符串类型的字符,但是你不需要知道具体用于存储这些字符的内部机制。你不知道任何关于对象使用本身与它的字符直接工作的内部行为,但是你需要知道你预计与对象如何交互,也许是为了让它处理特定字符或者请求一个新对象把所有原始字符转换为大写。

在objective - c中,类接口指定如何把给定类型的对象让其他对象使用。换句话说,它定义了公共接口在类的实例和外部世界之间。


Mutability Determines Whether a Represented Value Can Be Changed


一些类定义的对象是不可变的。这意味着在创建一个对象时,内部的内容必须被设置,随后,不能被其他对象改变。在objective - c中,所有NSString和NSNumber对象是不可变的。如果你需要代表一个不同的数字,你必须使用一个新的NSNumber实例。

一些不可变类还提供了一个可变的版本。如果你特别需要在运行时改变字符串的内容,例如附加字符用于接收到网络连接,您可以使用 NSMutableString 类的实例对象。这个类的实例的行为就像NSString对象,除了他们提供功能改变对象表示的字符串。

尽管NSString和NSMutableString 是不同的类,但是它们有很多相似之处。他们之间不是从头编写两个完全独立的类,刚好有类似的行为,而是有意义的利用了继承特性。

Classes Inherit from Other Classes


在自然世界中,将动物分类为许多群组,诸如物种,属,和科。这些团体是分等级的,这样,多个物种可能属于一个属,多个属一个科。

例如,大猩猩,人类和猩猩有一些明显的相似之处。虽然他们属于不同的种类,甚至是不同的属,部落,和亚科,但是他们在分类学上是有关联的,因为他们都属于同一个科(称为“人科”),如图1 - 1所示。

Figure 1-1  Taxonomic relationships between species



在面向对象编程的世界中,对象也分为层组。对象只是简单的组织成类,而不是在不同层级使用不同的术语,如属或物种。以同样的方式,人类作为人科家族的成员继承了某些特征,一个类可以继承父类的功能。

当一个类继承自另一个类,子类继承所有父类定义的方法和属性。它也有机会来定义自己的额外的行为和属性,或覆盖父类的行为。

在objective - c字符串类这个例子中,,类NSMutableString指定类继承自NSString,如图1 - 2所示。NSString所提供的所有功能NSMutableString都可以使用,如查询特定的字符或请求新的大写字母字符串,但NSMutableString补充了新方法,允许您添加、插入、替换或删除子字符串和单个字符。


Figure 1-2  NSMutableString class inheritance

The Root Class Provides Base Functionality


所有生物体分享一些基本的“生命”的特征,以同样的方式 ,一些功能对objective - c所有对象是通用的。

当一个objective - c对象需要与另一个类的实例进行交互的时候,希望其他类提供了某些基本特性和行为。出于这个原因,objective - c定义了一个根类被绝大多数其他的类继承,称为NSObject。当一个对象遇到另一个对象,它预计至少可以交互使用NSObject类描述定义的基本行为。

当你定义自己的类时,你应该至少从NSObject继承。一般来说,你应该找到一个Cocoa 或 Cocoa Touch对象来继承,这个对象提供了你想要的近似的功能。

如果你想定义一个自定义按钮用于一个iOS应用程序,例如,提供的UIButton类没有提供足够的可自定义属性来满足您的需要,那么创建一个新类继承自UIButton继承自NSObject  更有意义。如果你只是从NSObject继承,为了让你的用户按钮按预期的方式进行你需要重复定义所有复杂的视觉交互和通信UIButton类。此外,通过从UIButton继承,子类自动获得任何未来可能应用于内部UIButton行为的增强或bug修复,。

UIButton类本身定义继承UIControl类(描述在iOS上所有用户界面控件的基本行为)。UIControl类继承自UIView(常见功能是屏幕显示的使用)。 UIView继承自UIResponder(允许响应用户输入如点击、手势或震动)。最后,在树的根, UIResponder继承自NSObject,如图1 - 3所示。


Figure 1-3  UIButton class inheritance


这一连串的继承意味着任何自定义子类UIButton不仅继承UIButton本身的功能,也从每个超类继承相应的功能。最终你会得到一个类的对象,比如一个按钮,可以显示在屏幕上,响应用户输入,与任何其他基本的Cocoa Touch对象交互。

记住你所需要使用的类的继承链是很重要的,这样你就能弄明白它到底能做什么。类的参考文档提供了Cocoa和Cocoa Touch框架的描述,例如,允许从任何简单的类浏览它的超类。如果你在一个类接口或引用里找不到你想要的,它很可能定义或记录在超类里。

The Interface for a Class Defines Expected Interactions

面向对象编程的好处之一是你只需要知道一个类与她的实例如何交互。更具体地说,在设计一个对象的时候,你应该隐藏其内部实现的细节。

如果你在 iOS应用程序 使用一个标准的UIButton类 ,你不需要担心像素是如何操纵的,以使得按钮出现在屏幕上。你只是需要知道,你可以改变某些属性,如按钮的标题和颜色,请相信当你将它添加到您的视觉界面,它将以你期望的方式 正确 显示


This information goes into the interface for your class—it defines the way you intend other objects to interact with instances of your class. The public interface is described separately from theinternal behavior of your class, which makes up the class implementation. In Objective-C, the interface and implementation are usually placed in separate files so that you only need to make the interface public.

当你定义自己的类,您需要先弄清楚这些公共属性和方法。你想要什么属性公开访问?你应该允许这些属性被改变吗?其他对象如何与你的类的实例交互?

当信息进入你定义的类接口--对象是以你想要的方式与你的类的实例进行交互。公共接口内部的方法是分开描述的,这就是类的实现。在objective - c中,接口和实现通常放置在不同的文件中,这样您只需要公开接口。

Basic Syntax

objective - c语法中这样声明一个类的接口:

@interface SimpleClass : NSObject
 
@end

这个例子声明了一个名为SimpleClass的类,它们从NSObject继承。

公共属性和行为定义声明在 @ interface内 。在这个例子中,没有指定超类,所以 实例SimpleClass 唯一可用的功能将从NSObject继承。

Properties Control Access to an Object’s Values

对象属性往往用于公共访问。例如,在一个档案应用程序里你定义一个类来表示一个人,您可能需要的属性是用字符串代表一个人的姓和名。

声明这些属性应该添加到接口内部,如下:

@interface Person : NSObject
 
@property NSString *firstName;
@property NSString *lastName;
 
@end

在这个例子中,Person类声明两个公共属性,这两个是NSString类的实例。

这些属性都是objective - C对象,所以他们使用*表明C指针。他们的声明就像任何其他变量声明在C语言中那样,需要一个分号结尾。

您可能决定添加一个属性来代表一个人的出生年份,允许你通过年龄排序而不是通过名字。您可以这样:

@property NSNumber *yearOfBirth;

但只是存储一个简单的数值而使用NSNumber可能被视为太过了。另一个选择是使用C提供的基本类型,如一个整型:

@property int yearOfBirth;
Property Attributes Indicate Data Accessibility and Storage Considerations

到目前为止所有的例子声明的属性都是公共访问。这意味着其他对象既可以读取也可以改变属性的值。

在某些情况下,您可能定义一个并不是可改变的属性。在现实世界中,一个人必须填写大量的信息来改变记录中的姓或名。如果你编写一个正式的记录程序,你可以选择一个人的名字的公共属性被指定为只读,要求任何更改请求都要通过一个间接的对象负责验证,批准或拒绝它。

objective - c中property声明可以包括属性,用来表示是否一个属性是只读的。在正式的记录应用程序中,Person类接口看起来像这样:

@interface Person : NSObject
@property (readonly) NSString *firstName;
@property (readonly) NSString *lastName;
@end

property属性被定义在关键字@property括号之后,详细描述参见Declare Public Properties for Exposed Data.

Method Declarations Indicate the Messages an Object Can Receive


到目前为止的示例包括一个类,描述了一个典型的对象模型,或者说是一个对象主要封装了数据。在Person类的例子中,有可能不需要任何之外的功能,除了能够访问这两个声明的属性。然而,大多数类,除了包括属性,还包括行为方法

鉴于objective - c软件是由一个大型的网络对象组成的,重要的是要注意,这些对象可以相互发送消息。在objective - c中,一个对象发送一个消息到另一个对象通过调用一个对象的方法。

objective - C方法在概念上类似于C和其他编程语言标准函数,虽然语法有很大的不同。一个C函数声明如下:

void SomeFunction();

The equivalent Objective-C method declaration looks like this:

- (void)someMethod;

上面的情况,方法是没有参数的。C语言中关键字void 被用来表示函数没有任何返回值。

The minus sign (-) at the front of the method name indicates that it is an instance method, which can be called on any instance of the class. This differentiates it from class methods, which can be called on the class itself, as described in Objective-C Classes Are also Objects.

减号(-)在前面的方法名称表明它是一个实例方法(或者叫对象方法),它可以被任何类的实例调用。这样用于区分类方法,类方法只能被类本身调用。

参见 Objective-C Classes Are also Objects

与C函数原型一样,一个方法声明一个objective - C类接口中,就像任何其他C语句,需要以分号终止。

Methods Can Take Parameters

如果你需要定义一个带一个或者多个参数的方法,那么OC中的语法与典型的C语法有很大的不同哦。

对于C函数,是这样声明的:

void SomeFunction(SomeType value);

An Objective-C method declaration includes the parameters as part of its name, using colons, like this:

- (void)someMethodWithValue:(SomeType)value;

方法的返回值,括号内参数的类型如同C语言一样。

如果你序言多个参数,OC中的语法又一次很不同于C语言。多个参数在C语言中时直接声明在括号内的,用逗号分隔;但是在OC中,一个方法有两个参数像这样声明:

- (void)someMethodWithFirstValue:(SomeType)value1 secondValue:(AnotherType)value2;

这个例子中,value1和value2 就好像变量一样,当方法被调用时她们的名字被用在实现中。

有些编程语言允许函数定义所谓的命名参数,重要的是要注意,在objective - c不允许这样。在方法调用中,参数的顺序必须与声明时的顺序匹配,实际上,secondValue:也是方法声明的一部分

someMethodWithFirstValue:secondValue:

这样的特性可以帮助OC语言增强可读性,参见You Can Pass Objects for Method Parameters.

Note:上面的value1,value2名称使用严格来说并不方法声明的一部分,这意味着在你实现的声明中,不需要使用完全相同的值的名字。唯一的要求就是,签名匹配,这意味着你必须有方法的名称以及参数和返回类型。

As an example, this method has the same signature as the one shown above:

- (void)someMethodWithFirstValue:(SomeType)info1 secondValue:(AnotherType)info2;
These methods have different signatures to the one above:

- (void)someMethodWithFirstValue:(SomeType)info1 anotherValue:(AnotherType)info2;
- (void)someMethodWithFirstValue:(SomeType)info1 secondValue:(YetAnotherType)info2;

Class Names Must Be Unique


在一个应用中,类的名字必须是独一无二的,甚至是在包含的库或者框架中。在一个工程中,如果你企图创建一个同名的类名,会出现一个编译错误。

出于这个原因,在你定义的任何类中,名字前面加上前缀是明智的选择。,使用三个或更多的字母。这些字母可能与你当前的应用有关,或者一个可重用的代码框架的名称,或者只是你的名字的首字母。

All examples given in the rest of this document use class name prefixes, like this:

@interface XYZPerson : NSObject
@property (readonly) NSString *firstName;
@property (readonly) NSString *lastName;
@end

Historical Note: If you’re wondering why so many of the classes you encounter have an NS prefix, it’s because of the past history of Cocoa and Cocoa Touch. Cocoa began life as the collected frameworks used to build apps for the NeXTStep operating system. When Apple purchased NeXT back in 1996, much of NeXTStep was incorporated into OS X, including the existing class names. Cocoa Touch was introduced as the iOS equivalent of Cocoa; some classes are available in both Cocoa and Cocoa Touch, though there are also a large number of classes unique to each platform.

Two-letter prefixes like NS and UI (for User Interface elements on iOS) are reserved for use by Apple.


相比之下,方法和属性名,只需要在类中定义它们是唯一的。虽然每一个C函数在一个应用程序必须有一个唯一的名称,这是完全可以接受的(通常是可取的)为多个objective - C具有相同名称的类方法。你不能在同一个类声明中定义多次同一方法,然而,如果你想覆盖一个继承自一个父类的方法,您必须使用准确的名称,这个名称是在父类中声明的。

正如方法一样,一个对象的属性和实例变量(参见Most Properties Are Backed by Instance Variables)只是在他们声明的类中必须是独一无二的。如果你要使用全局变量,她的名字在一个程序或工程中都是独一无二的。

更多的命名建议以及惯例参见Conventions

The Implementation of a Class Provides Its Internal Behavior

 一旦你定义的接口类,包括属性和方法用于公共访问,您需要编写代码来实现类的行为。

如前所述,接口通常是放置在一个专门的文件,通常被称为一个头文件,通常文件扩展名. h。objective - c类的实现在一个源代码文件扩展名. m

无论何时,你都需要在编译源代码文件之前告诉编译器接口定义在头文件中为这个目的,objective - c提供了一个预处理器指令#import。类似于C # include指令,但确保编译的头文件只包含一次。

注意,预处理器指令是不同于传统的C语句的,不使用分号终止。

Basic Syntax

The basic syntax to provide the implementation for a class looks like this:

#import "XYZPerson.h"
 
@implementation XYZPerson
 
@end

如果你定义了方法在类的接口中,那么你需要在这个文件中实现这个方法。

Implementing Methods


一个简单的类接口有一个方法,,就像这样:

@interface XYZPerson : NSObject
- (void)sayHello;
@end

the implementation might look like this:

#import "XYZPerson.h"
 
@implementation XYZPerson
- (void)sayHello {
    NSLog(@"Hello, World!");
}
@end

下面的例子使用了NSLog()函数来日志消息输出到控制台。类似于标准C库的printf()函数,传入一个参数是变量的,第一个必须是一个objective - C字符串。

方法的实现类似于C函数定义,因为它们都使用括号包含相关的代码。此外,该方法的名称必须与原型相同, 参数和返回值必须匹配。

objective - C 从C 继承了大小写敏感性,所以这个方法:
- (void)sayhello {
}

通常会被编译器视为与sayHello方法完全不同。

通常方法名以小写字母开头。objective - C约定的方法是使用更具描述性的名称。如果一个方法名涉及多个单词,使用驼峰式大小写(利用每个新单词的第一个字母),使它们容易阅读。

Note also that whitespace is flexible in Objective-C. It’s customary to indent each line inside any block of code using either tabs or spaces, and you’ll often see the opening left brace on a separate line, like this:

在objective - c中还要注意空格的灵活运用。习惯性的使用tab或whitespace缩进任何的代码块里的每一行,你会经常看到左括号在单独的行,如下:

- (void)sayHello
{
    NSLog(@"Hello, World!");
}

Xcode,苹果公司的集成开发环境(IDE)用来创建OS X和iOS软件,会根据用户自定义的设置缩进代码,在 Xcode Workspace Guide中更改信息,

 你会看到更多的方法实现,在下一章的例子中:  Working with Objects

Objective-C Classes Are also Objects

在objective - c中,类本身就是一个隐含类型的对象。如前面所示的声明实例的语法,类不能真正的拥有属性,但他们可以接收消息。

一个 类方法 的典型应用是作为工厂方法,这是一个替代对象分配和初始化过程,参见Objects Are Created Dynamically。例如,NSString类,有各种各样的工厂方法可以创建一个空字符串对象,用特定的字符或字符串对象初始化,包括:

+ (id)string;
+ (id)stringWithString:(NSString *)aString;
+ (id)stringWithFormat:(NSString *)format, …;
+ (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
+ (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;

如这些例子所示,类方法是用使用+,这区分实例方法使用的-。

类方法的原型可以声明在类接口,就像实例方法原型那样。类方法实现与实例方法一样,在@implementation块中。

Exercises 练习

Note: In order to follow the exercises given at the end of each chapter, you may wish to create an Xcode project. This will allow you to make sure that your code compiles without errors.

Use Xcode’s New Project template window to create a Command Line Tool from the available OS X Application project templates. When prompted, specify the project’s Type as Foundation.

  1. Use Xcode’s New File template window to create the interface and implementation files for an Objective-C class called XYZPerson, which inherits from NSObject.

  2. Add properties for a person’s first name, last name and date of birth (dates are represented by the NSDate class) to the XYZPerson class interface.

  3. Declare the sayHello method and implement it as shown earlier in the chapter.

  4. Add a declaration for a class factory method, called “person”. Don’t worry about implementing this method until you’ve read the next chapter.

    Note: If you’re compiling the code, you’ll get a warning about an “Incomplete implementation” due to this missing implementation.



@interface XYZPerson : NSObject

@property NSString *firstName;
@property NSString *lastName;
@property NSDate *birthDay;

-(void) sayHello;
+(void) person;

@end





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值