Objective-C 基础教程第三章,面向对象编程基础知

0x00 前言

书中的这章节主要是对零基础的人介绍面向对象编程的基础知识,一般学过高级编程语言的基本都会涉及到面向对象编程的知识,所以可以略过。

术语:OOP的解释

面向对象编程(Object-Oriented Programming)的首字母缩写为:OOP,这是一种编程技术,最初是为了编写模拟程序开发的。OOP很快就俘虏了其他种类软件(比如涉及图形用户界面的软件)开发者的心。很快OOP就成为了业内一个非常重要的流行词。它被誉为具有魔力的颜色子弹,可以使编程工作变得简单而愉悦。

在讨论OOP之前,先来看看OOP的一个关键概念:间接(indirection)

0x01 间接(indirection)

间接是一种概念,为什么要用间接从书本上的几个例子中,我大概体会到应该就是为了可变性,比如说我在代码里面有个循环语句,然后有个printf每次输出1-xxx的值,那么我要改循环次数的时候就需要每次将printf里面的xxx改成循环的次数,如果用变量来代替的话我只需要改一次循环次数即可。

还有就是用文件间接的方式,比如我要输出一堆数据,都需要提前定义一个列表或者数组,那么需求有变动的时候我就要每次改这些变量里面的值,但是如果我程序从文件里面读取这些数据,我只需要修改下文件里面的内容即可,所以可变动性就特别好。

0x02 面向对象编程中使用间接

在书中看完间接的知识后, 对间接的概念大致有了个了解。在面向对象编程中(OOP),间接可以说是他的核心。

OOP使用间接来获取数据,就像我们在之前的例子中使用变量、文件和参数所做的那样。OOP真正的革命性在于它使用间接来调用代码!不是直接调用某个函数,而是用间接调用!

只要理解了这一点,你就算掌握了OOP的内涵了。其他一切都是通过间接产生的引申效果。

面向过程编程

首先来看两个例子,分别是面向过程编程和面向对象编程的代码,书中说到:过程式编程建立在函数之上,数据为函数服务。

//*********************************************************************
//利用纯C语言和过程式编程方式绘制几何体的形状。
//
//《Object-C 基础教程》 03.08 Shapes-Procedural
//**********************************************************************
#import <Foundation/Foundation.h> //----------------------------------------变量声明----------------------------------
//几何体形状类型
typedef enum{
kCircle, //圆圈
kRectangle,//矩形
kEgg, //鸡蛋
}ShapeType; //几何体颜色类型
typedef enum{
kRedColor, //红色
kGreenColor,//绿色
kBlueColor, //蓝色
}ShapeColor; //几何体轮廓结构体
typedef struct{
int x,y,width,height;
}ShapeRect; //几何体结构体
typedef struct{
ShapeType type;
ShapeColor fillColor;
ShapeRect bounds;
}Shape;
void drawShapes(Shape shapes[],int num)
//------------------------------------------------------------------------------- //入口点代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
Shape shapes[3]; //圆形数据赋值
ShapeRect rect0 = {0,0,10,30}; //x,y坐标与宽和高数据
shapes[0].type = kCircle; //几何体类型
shapes[0].fillColor = kRedColor;//几何体颜色
shapes[0].bounds = rect0;
//矩形数据赋值
ShapeRect rect1 = {30,40,50,60};
shapes[1].type = kRectangle;
shapes[1].fillColor = kGreenColor;
shapes[1].bounds = rect1;
//鸡蛋数据赋值
ShapeRect rect2 = {15,18,37,29};
shapes[2].type = kEgg;
shapes[2].fillColor = kBlueColor;
shapes[2].bounds = rect2; //绘制几何体
drawShapes(shapes,3);
}
return 0;
}
//面向过程方式drawShapes
void drawShapes(Shapes shapes[],int count)
{
for(int i=0;i<count;i++)
{
switch(shapes[i].type){
case kCircle:
drawCircle(shapes[i].bounds,shapes[i].fillColor);
break;
case kRectangle:
drawRectangle(shapes[i].bounds,shapes[i].fillColor);
break;
case kEgg:
drawEgg(shapes[i].bounds,shapes[i].fillColor);
break;
case kTriangle:
drawkTriangle(shapes[i].bounds,shapes[i].fillColor);
break;
}
}
}

从书中的例子可以看出,面向过程编程中,如果我们要让程序扩展一下,比如不仅能绘制各种形状,还必须计算这些形状的面积,并判断鼠标光标是否位于这些形状中。在这种情况下,就必须修改每个对形状执行操作的函数,修改过去正常工作的代码很可能引入新的错误,所以在这点上面向过程编程极其不方便,就需要用到OOP(面向对象编程)概念了。

面向对象编程

面向对象编程则以程序的数据为中心函数为数据服务。在OOP中,不再重点关注程序中的函数,而是专注于数据。

在OOP中,数据通过间接方式引用代码,什么意思呢?

就是代码可以对数据进行操作,不是向面向过程那样,通知drawRectangle函数绘制一个根据这种形状的图形,而是要求形状绘制自身。(借助间接的强大功能,这些数据能够知道如何查找相应的函数来进行绘制)。

对象是什么?

就是和C语言中的struct一样,神奇的是它能够通过函数指针查找与之相关的代码。

如下图:展示了4种Shape对象:两个正方形、一个圆形和一个椭圆形。(每个对象都能查找相应的函数并实现其绘图功能)

每个对象都有自己的draw函数,知道如何绘制自身的形状。

(我们直接将之前的面向过程代码,改成面向对象的代码,只需要改动一个函数就行。)

void drawShapes(id shapes[],int count)
{
for(int i=0;i<count;i++)
{
id shape = shapes[i];
[shape draw];
}
}

改完了,代码是不是变的超级简洁啊!

解释下这段代码的意思,其中id属于OC中的泛型,他有点类似Java中的Object,就是用id可以引用任何类型的对象。

对象是一种包含代码的struct结构体,所以id实际上是一个指向结构体的指针

[shape draw],这一句代码的意思是通知shape对象发送draw消息或者向shape发送draw消息,至于形状如何实际绘制自身的图形,取决于shape的实现。

思考?

向对象发送消息后,如何调用所需要的代码呢?就是如何才能触发比如draw这个函数呢?

解答:

这就需要叫做的幕后帮手来协助完成这个任务,请看如下图:

可以从图中看出,其实他就是利用了指针来进行间接,方面我们扩展类的代码,当我们需要给圆形添加一些新功能,一些新属性时候就可以直接在类的代码里面进行编写,我们也不需要修改之前对象调用的代码,这样确实也不容易导致错误。

0x03 OC面向对象 术语

  • 类(class) 其实就是一个结构体,用来描述对象的类型。
  • 对象(object) 包含值和(this指针)指向其类的隐藏指针的结构体。
  • 实例(instance)是“对象”的另外一种称呼。
  • 消息(message)是对象可以执行的操作,用于通知对象去做什么。
  • 方法(method)为了响应消息而运行的代码。(个人理解应该是private的类函数)
  • 方法调度(method dispatcher)是Object-C的一种机制,用于推测执行什么方法以响应某个特定的消息。
  • 接口(interface)是类为对象提供的特性描述。例如,Circle类的接口声明了Circle类可以接受draw消息。
  • 实现(implementation)是使接口能正常工作的代码。

0x04 OC语言中的OOP

根据书本中的相关内容学习了OOP的一些基础概念后,终于可以来体验OC中的OOP了。

@interface

创建某个特定类的对象之前,Object-C编译器需要一些有关该类的信息,尤其是对象的数据成员(也就是编译器需要根据结构体的大小,结构体的成员,函数等等)进行一些列的初始化工作,好方便转换成汇编代码?应该是这样理解。所以(我们可以使用@interface指令把这些信息传递给编译器)。ps:说明这编译器不太智能?为啥Windows下C++都不用搞这么麻烦! 可能是因为C++用了Class关键字来传递的。

//**********************************************************
/* Circle类接口 *
/***********************************************************/
@interface Circle : NSObject
{
ShapeColor fillColor;
ShapeRect bounds;
} - (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end

根据书本中的例子,我们对上面代码进行详细的分析,上面代码的语法都比较陌生,从@interface开始,在第二章中说过只要出现@符号,就可以把它看成是对C语言的扩展,然后上面也说过了@interface是用来把类信息传递给编译器的。

接着最尾部是@end关键字,应该就是告诉编译器@end以上的都是这个类的信息。

接着@interface后面跟着的是类名,代表告诉编译器这是Circle类的接口,然后:NSObject代表的是继承自NSObject类。

然后{...}里面的部分是告诉编译器Circle对象所需要的数据成员,其中这里面的成员被称为Circle类的实例变量

最后几行代码有点类似C语言中的函数原型,不过略微有点区别,主要就是多了-():这些奇怪的符号。

这是OC中的方法声明语法,其解释如下。

  • -(void) 其中这个减号代表的是OC方法的声明,主要用来区分C语言原型函数,还有减号代表的是对象的方法加号代表的是类的方法。
  • setFillColorsetBoundsdraw这些代表的是方法名,不过前面两个和最后一个有区别就是多了:
  • :,这个在OC中叫中缀符语法,方法的名称以及其参数都是合在一起的,所以最后一个没有参数的函数就没有这东西。
  • 带中缀符号的方法调用时候可以这样调用,[circle setFillColor: kRedColor];,带有两个中缀符的时候就[testThing setStringValue:@"hello there" color:kBlueColor];
  • 参数的类型是在()中指定的。

@implementation

说过了带@就是C语言的扩展,@interface用于定义类的接口,通常接口被称为APIApplication Programming Interface。而真正能使对象运行的代码都在@implementation实现

//**********************************************************
/* Circle类接口实现 *
/***********************************************************/
@implementation Circle
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
} - (void) setBounds:(ShapeRect) b
{
bounds = b;
}
@end

这是OC中的类声明语法,解释如下:

  • @implementatation英语翻译为实现,如其名就是告诉编译器接下来这些代码是用于实Circle类的。

  • - (void) setFillColor:(ShapeColor) c这代码与@interface处基本差不多,只是他结尾没有;,代表不是声明语句,而且参数名是可以改变的。

  • fillColor = c,类似C++中的this->fillColor = c,在OC中默认的隐藏this指针为self,也就是self->fillColor = c

instantiation(实例化对象)

我们学会了如何声明类接口,并且实现类代码后,最后当然是要去调用该类的对象去实际操作,那么在OC中如何实例化对象呢?

在OC中很方便可以把类当成对象去发送消息,所以我们实例化一个对象的时候,其实只要发送一个new消息就行,比如Circle circle = [Circle new];,然后调用之前演示过了用[circle setFillColor: kRedColor],tips:(由于对象的局部变量只在对象的实例中有效,因此我们称它们为实例变量,通常简写成ivar。)

0x05 第三章小节

本章是面向对象的概念和定义,我写的也比较多。首先是介绍了间接的这个概念,然后又从面向过程编程开始逐步过渡到面向对象编程,之后也用了大量的例子来进行实验,最后过渡到OC中的面向对象编程,其中学习到了很多关键字比如,@interface接口声明,@implementation类接口实现,:中缀符,[xx xx]通知对象发送xx消息,instantiation实例化对象可以通过发送new 消息给类来进行创建一个新的对象,接着第四章开始学习继承。

Objective-C 基础教程第三章,面向对象编程基础知的更多相关文章

  1. Python学习-第三天-面向对象编程基础

    Python学习-第三天-面向对象编程基础 类和对象 简单的说,类是对象的蓝图和模板,而对象是类的实例.这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的 ...

  2. 那些年被我坑过的Python——玄而又玄(第六章 面向对象编程基础)

    面向对象编程: 面向对象顾名思义,就是把组织代码的粒度从函数级别抽象到对象级别,对象是通过类来生成的,类可以想象为模板或进本框架而对象是在原有模板或框架的基础上增加详细信息的实体,类,有分类.聚类的含 ...

  3. python基础教程-第三章-使用字符串

    本章将会介绍如何使用字符串何世华其他的值(如打印特殊格式的字符串),并简单了解下利用字符串的分割.联接.搜索等方法能做些什么 3.1 基本字符串操作 所有标准的序列操作(索引.分片.乘法.判断成员资格 ...

  4. 【blockly教程】第二章 Blockly编程基础

    2.1 Blockly的数据类型 2.1.1 数据的含义  在计算机程序的世界里,程序的基本任务就是处理数据,无论是数值还是文字.图像.图形.声音.视频等信息,如果要在计算机中处理的话,就必须将它们转 ...

  5. Python 进阶(三)面向对象编程基础

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkMAAAFGCAIAAADmfgziAAAgAElEQVR4nOx993vT1v7/93/5EEt2Eg

  6. 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础

    第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...

  7. [.net 面向对象编程基础] (1) 开篇

    [.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...

  8. Java基础知识二次学习--第三章 面向对象

    第三章 面向对象   时间:2017年4月24日17:51:37~2017年4月25日13:52:34 章节:03章_01节 03章_02节 视频长度:30:11 + 21:44 内容:面向对象设计思 ...

  9. 进击的Python【第六章】:Python的高级应用(三)面向对象编程

    Python的高级应用(三)面向对象编程 本章学习要点: 面向对象编程介绍 面向对象与面向过程编程的区别 为什么要用面向对象编程思想 面向对象的相关概念 一.面向对象编程介绍 面向对象程序设计(英语: ...

随机推荐

  1. 利用quake捡洞

    quake一开漏洞全靠捡 定位资产 通过主域名定位子域名资产 domain:"target.com" 通过C段定位资产 ip: "1.1.1.1/24" 通过证 ...

  2. [爱偷懒的程序员系列]-Section 1. “懒”是一切需求的根源

    一直认为"懒"推进了科技的发展,因为"懒"而促生了各种各样的需求.科技的进步加速了各种信息的交互频率,站在台面上说是因为业务需要提高效率,成本需要降低,服务需要 ...

  3. Mysql 死锁分析

    1. 结论 死锁检查机制 当事务A需要获取一个行锁时(例如更新一行数据),假如需要获取行1的锁 检查其他事务有没有已获取了行1的锁. 如果有,例如事务B已获取了行1的锁. 继续检查事务B在等待的锁,如 ...

  4. Tomcat下载安装以及配置方法

    Tomcat环境变量配置方法 注意一定要在java环境配置成功之后再来配置tomcat.我这里仅展现在Windows系统下载的安装方法 Tomcat下载地址如下: https://tomcat.apa ...

  5. 【Azure Developer】使用 Azure Python SDK时,遇见 The resource principal named https://management.azure.com was not found in the tenant China Azure问题的解决办法

    问题描述 在使用Python SDK时候,登录到China Azure (Mooncake)并访问AlertsManagement资源时候,时常遇见  EnvironmentCredential: A ...

  6. 学习Java第15天

    今天所做的工作: 学习了HTML的基本标签,vs code的基本使用 明天工作安排: 继续学习html 目前所遇到的大都是HTML标签数量多,较复杂的问题,继续找规律记忆吧.

  7. linux apache软件安装

    安装提示 Linux下,源码的安装一般由3个步骤组成:配置(configure).编译(make).安装(make install). 过程中用到"configure --prefix=安装 ...

  8. 微服务架构 | 10.1 使用 Sleuth 追踪服务调用链

    目录 前言 1. Sleuth 基础知识 1.1 Sleuth 原理 2. 在服务中使用 Sleuth 追踪 2.1 引入 pom.xml 依赖文件 2.2 查看日志信息 最后 前言 参考资料: &l ...

  9. NOIP2018 Day2T2 填数游戏

    下面先给出大家都用的打表大法: 首先我们可以发现 \(n \le 3\) 的情况有 \(65pts\),而 \(n\) 这么小,打一下表何乐而不为呢?于是我写了一个爆枚每个位置再 \(check\) ...

  10. Atcoder ARC-070

    A 可以发现的是,次数的下界一定是使得 \(\frac{n(n + 1)}{2} \ge X\) 最小的 \(n\). 稍加思考可以发现,只需要在某一时刻停一下一定能在下界的次数内跳到恰好 \(X\) ...