7-类、对象和方法

最后更新于:2022-04-01 00:17:09

Objective-C作为一种面向对象的编程语言, 具有面向对象的基本特征,  即: 封装、 继承和多态。  主要介绍ObjectiveC中有关面向对象基本概念: 类、 对象、 方法和属性等。 也就是面向对象程序设计的一些关键概念,主要关注Objective-C定义类相关的语法。 OC面向对象方面的概念和其它语言差不多。相比其他语言更接近C++。 对象就是一个物件。面向对象的程序设计可以看成一个物件和你想对它做的事情。 对象(名词)----实现(动词),先定义类(Class),再定义方法(Method)。 #### C语言是典型的面向过程性语言。 在C语言中,通常是先考虑要实现什么,然后才关注对象,这几乎总是与面向对象的思考过程相反。 实现(动词)----对象(名词),先定义函数(Function),再定义模块(Module)。 类的独特存在就是一个实例,对实例执行的操作称为方法。 在某些情况下,方法可以应用于类的实例或类本身。 对象使用方法可以影响对象的状态。 关键概念:对象是类的独特表示,每个对象都包含一些通常对该对象来说是私有的信息(数据)。方法提供访问和改变这些数据的手段。 Objective-C采用特定的语法对类和实例应用方法: [ ClassOrInstance method]; 请求一个类或实例来执行某个操作时,就是向它发送一条消息,消息的接收者称为Receiver。所以,可以用另外一种方式描述: [ receiver message]; Objective-C的Method操作执行,一种理解是发送消息,另外一种是方法调用。 前一种更贴近OC的思想。 Objective-C的类声明和实现包括两个部分:接口部分和实现部分。 ~~~ @interface Song: NSObject { … … } … … @end @implementation Song … … @end ~~~ 同样的,程序在逻辑上就分为下面3个部分: @interface @implementation program #### 接口部分 @interface部分用于描述类和类的方法; @implementation部分用于描述数据(类对象的实例变量存储的数据),并实现在接口中声明方法的实际代码; 主要定义了类名 、 继承的父类、 实现的协议、 成员变量和方法等信息。 举例如下: 一首好听的音乐,下面的代码是Song类的接口部分声明。 ~~~ @interface Song : NSObject { NSString *title; NSString *artist; long int duration; } - (void)start; - (void)stop; - (void)seek:(long int)time; @end ~~~ program部分的程序代码实现了程序的预期目的。 @interface部分一般格式如下: @interface NewClassName: ParentClassName propertyAndMethodDeclarations; @end 按照约定,类名以大写字母开头。 实例变量、对象以及方法的名称,通常以小写字母开头。 确定名称时,要遵循找到能反映变量或对象使用意图的名称。 程序具有更强的自解释性(Self-explanatory) 制定名称的规则相当简单:名称必须以字母或下划线(_)开头, 之后可以使任何大小写字母、下划线或者数字的组合。 另外像$空格等都是非法,记住不能数字开头、不能使用保留字。 再次强调,Objective-C是大小写敏感的。sum、Sum、SUM均表示不同的变量。 #### 实现部分 使用关键字@implementation, 主要实现了在接口部分定义的方法等信息。  ~~~ @implementation部分的一般格式如下: @inplementation NewClassName { memberDeclarations; } methodDefinitions; @end ~~~ 需要注意的是:使用@synthesize指令能让编译器自动为你生成一些方法。 举例如下: 下面的代码是Song类的实现部分声明。 ~~~ @implementation Song - (void)start { //开始播放 } - (void)stop { //停止播放 } - (void)seek:(long int)time { //跳过时间 } @end ~~~ 接口和实现的要求: 接口文件包含类的公开信息,即能够与这个类的使用者共享一些信息。 另一方面,实现部分包含的是私有信息,即实例变量和代码。 #### 方法和消息 类或实例方法,开头为负号(-)表示实例方法,正号(+)表示类方法。 返回类型放在开头的负号或正号之后的圆括号中。 有参数时,在方法名后加冒号(:),再加上参数类型和参数名。 具体的如下例所示: -(int) currentAge; -(void) print; -(void) setNumber: (int) n; 方法类型 (返回类型) 方法名称 方法有参数 参数类型 参数名称 可见,Objective-C中方法定义非常古怪, 它遵循了SmallTalk语法风格, 它将一个方法名字分成几个部分。 ![](file:///C:/Users/Administrator/AppData/Local/YNote/Data/danielzzu@163.com/6474e70e85cb435490ae24a0705e632d/clipboard.png) 如图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_5684a3f053bca.jpg) 再次解释说明: 定义了两个参数的方法,  第一个参数是anObject, 参数类型是id类型,  第二个参数是index, 参数类型是NSUInteger, 这叫做多重参数。  它的返回类型是void,  方法签名是insertObject:atIndex: 。  方法类型标识符中都“-” 代表方法是实例方法, “+” 代表方法是类方法,  关于实例方法和类方法我们将在后面内容中讨论。  如果上面的方法变成C或C++形式, 则是下面的样子的:  -(void) insertObjectAtIndex(id anObject, NSUInteger index)。 #### 消息发送 对于方法的调用通常也不称之为调用 , 而是称为发出消息, 操作符号不是“. ” 而是“[…] ” , 如下所示:  [myObject insertObject: ojb1 atIndex:0]; 即向myObject对象发出一个消息insertObject:atIndex: 。 而在实际使用时候这两种叫法都会用 , 这不是严格划分。 alloc是allocate的缩写。 如果向某个类发送alloc消息,便获得该类的新实例。 这个alloc方法继承自父类。alloc方法保证对象的所有实例都变成初始状态。 当然想要适当的方法时,必须重新初始化,调用init方法。 经常地情况是把alloc和init合在一起,或者直接使用new方法。 例如: ~~~ Fraction *myFraction;   myFraction = [Fraction alloc];//类方法   myFraction = [myFraction init];//实例方法      Fraction *myFraction = [[Fraction alloc] init];//二合一      Fraction *myFraction = [Fraction new];//类方法,new包含alloc和init   ~~~ 记住,方法执行的上下文环境就是接收到消息的对象。 取值方法(get)和赋值方法统(set)称为访问方法(accessor)。 这就是数据封装的原则,通过使用方法来访问对“外界”隐藏的数据。 使用一个类的程序结束本章: ~~~ //   //  main.m   //  3_2_class_object_method   //   //  Created by haomengzhu on 14-11-01.   //  Copyright (c) 2014年 haomengzhu. All rights reserved.   //      #import       //-------- @interface section ----------   @interface Fraction: NSObject   -(void) print;   -(void) setNumerator: (int) n;   -(void) setDenominator: (int) d;   @end      //-------- @implementation section ----------   @implementation Fraction   {       int numerator;       int denominator;   }   -(void) print   {       NSLog(@"%i/%i", numerator, denominator);   }   -(void) setNumerator:(int)n   {       numerator = n;   }   -(void) setDenominator:(int)d   {       denominator = d;   }   @end      //-------- program section ----------      int main(int argc, const charchar * argv[])   {          @autoreleasepool {           Fraction *myFraction;                      // new object           myFraction = [Fraction alloc];           myFraction = [myFraction init];                      // set           [myFraction setNumerator: 1];           [myFraction setDenominator: 3];                      // print all           NSLog(@"Hello, World!");           [myFraction print];       }       return 0;   }   ~~~ 最后再来说说OC中的方法: #### 关于方法: 在编写新方法时,省略参数名不是一种好的编程风格,因为它是程序很难读懂并且很不直观, 特别是当使用的方法参数特别重要时,更是如此。 举例如下: 定义了Fraction类以及新方法: -(void)setTo:(int)n over:(int)d;  注意下面的使用方式: [aFraction set:1 :3]这是不好的 [aFraction set:1 over:3]这是好的 #### 再添加新方法: - (void)add:(Fraction *) f; 这条语句说明add:方法的参数是Fraction类对象的一个引用。 星号是必须的,所以声明(Fraction) f是不正确的。 #### 局部变量: 局部变量是基本的C数据类型,并没有默认的初始值,所以在使用前要先赋值。 局部对象变量默认初始化为nil。 和实例变量不同(它们在多次方法调用时保持自己的值),这些局部变量没有记忆力。 也就是说,当方法返回时,这些变量的值都消失了。 每次调用方法时,该方法中的局部变量都使用变量声明重新初始化一次。 #### 方法的参数: 方法的参数名也是局部变量。执行方法时,通过方法传递的任何参数都被复制到局部变量中。因为方法使用参数的副本,所以不能改变通过方法传递的原值。这一点很重要。 另外,如果参数是对象,可以更改其中的实例变量值。当你传递一个对象作为参数时,实际上是传递了一个数据存储位置的引用。正因为如此,你才能够修改这些数据。 #### static关键字: 在变量声明前加上关键字static,可以使局部变量保留多次调用一个方法所得的值。 和其它基本数据类型的局部变量不同。 静态变量的初始值为0。 此外,它们只在程序开始执行时初始化一次,并且在多次调用方法时保存这些数值。 记住:只能在定义静态变量和局部变量的方法中访问这些变量。
';