1.间接
-
1.1变量与间接
基本变量就是间接的一种实际使用
为避免在代码中修改数值,可以将数字放入某个变量中,添加一层间接
#import <Foundation/Foundation.h>
int main (int argc,const char *argv[]){
NSlog(@"The numbers from 1 to 5:");
for (int i = 1; i <= 5; i++) {
NSLog(@"%d\n",i);
}
return 0;
}
//使用间接
#import <Foundation/Foundation.h>
int main (int argc,const char *argv[]){
int count = 5;
NSlog(@"The numbers from 1 to %d:",count);
for (int i = 1; i <= count; i++) {
NSLog(@"%d\n",i);
}
return 0;
}
-
1.2使用文件名的间接
文件是间接的另一个示例
为避免在代码中修改数据,可以将数字放入某个文件中,添加一层间接
#import <Foundation/Foundation.h>
int main (int argc,const char *argv[]){
const char *words[4] = {"aardvark","abacus","allude","zygote"};
int wordCount = 4;
for (int i = 0; i < wordCount; i++) {
//strlen相当于sizeof
NSLog(@"%s is %lu character long",words[i],strlen(words[i]));
}
return 0;
}
//当需要换另一组单词,很麻烦
//另一个方法就是将所有的名字都移到代码之外的某个文件中,每行一个文字,这就是间接
#import <Foundation/Foundation.h>
int main (int argc,const char *argv[]){
FILE *wordFile = fopen ("/tmp/words.txt","r");//fopen()函数打开word.txt文件
char word[100];
//fgets()从文件中读取一行文本并将其放入字符数组word中
//fgets()调用会保留每行之间用来断行的换行符,但我们不需要它,因为如果留下来,换行符就会被计为单词中的一个字符。为了解决这个问题,我们将换行符换为\0,这表示字符串的结束。
while (fgets(word, 100, wordFile)){
word[strlen(word) - 1] = '\0';
NSLog(@"%s is %lu characters long",word,strlen(word));
}
fclose (wordFile);
return 0;
}
- 传递隐藏的参数是间接的又一个示例
2.在面向对象过程中使用间接
-
2.1过程式编程
使用过程式编程,要花时间连接数据和用来处理该数据的函数
数据类型对应正确的函数易出错
程序的扩展和维护很困难
//Shape程序
//绘制出一个红色的圆形,绿色的矩形,蓝色的椭圆形
#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 count);
//输出矩形区域信息和传递给他的颜色
void drawCircle(ShapeRect bounds,ShapeColor fillColor);
void drawRectangle(ShapeRect bounds,ShapeColor fillColor);
void drawEgg(ShapeRect bounds,ShapeColor fillColor);
//传入颜色值
NSString *colorName (ShapeColor colorName);
//主函数
int main(int argc, const char * argv[]) {
//声明我们要绘制形状的数组
Shape shapes[3];
//设计红色的圆形
ShapeRect rect0 = {0,0,10,30};
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;
}
void drawShapes (Shape shapes[], int count) {
for (int i = 0; i < 3; 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;
default:
break;
}
}
}
void drawCircle(ShapeRect bounds,ShapeColor fillColor){
NSLog(@"drawing a circle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
void drawRectangle(ShapeRect bounds,ShapeColor fillColor){
NSLog(@"drawing a rectangle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
void drawEgg(ShapeRect bounds,ShapeColor fillColor){
NSLog(@"drawing a egg at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
NSString *colorName (ShapeColor colorName){
switch (colorName) {
case kRedColor:
return @"red";
break;
case kGreenColor:
return @"green";
break;
case kBlueColor:
return @"blue";
break;
default:
break;
}
}
//运行结果
2018-10-02 14:33:03.021349-0700 图形[673:20069] drawing a circle at (0,0,10,30) in red
2018-10-02 14:33:03.021547-0700 图形[673:20069] drawing a rectangle at (30,40,50,60) in green
2018-10-02 14:33:03.021628-0700 图形[673:20069] drawing a egg at (15,18,37,29) in blue
Program ended with exit code: 0
-
2.2实现面向对象编程
在oop中,数据通过间接方式引用代码,代码可以对数据进行操作,要求这个数据绘制自身
代码下一篇文章详细解说
//使用oop的方式写Shape程序
#import <Foundation/Foundation.h>
//通过枚举指定几种可以绘制的不同形状
typedef enum {
kCircle,
kRectangle,
kEgg,
}ShapeType;
//通过枚举指定绘制形状时可用的几种颜色
typedef enum {
kRedColor,
kGreenColor,
kBlueColor,
} ShapeColor;
//使用一个结构体来描述一个矩形,该矩形指定屏幕上的绘图区域
typedef struct {
int x,y,width,height;
}ShapeRect;
//声明绘制函数
void drawShapes (id shapes[], int count);
//输出矩形区域信息和传递给他的颜色
NSString *colorName (ShapeColor colorName);
//Circle类接口
@interface Circle : NSObject {
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds:(ShapeRect) bounds;
- (void) draw;
@end
//Circle类实现
@implementation Circle
-(void)setFillColor:(ShapeColor)c{
fillColor = c;
}
-(void)setBounds:(ShapeRect)b{
bounds = b;
}
-(void)draw{
NSLog(@"drawing a Circle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
@end
//Rectangle类接口
@interface Rectangle: NSObject {
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds:(ShapeRect) bounds;
- (void) draw;
@end
//Rectangle类实现
@implementation Rectangle
-(void)setFillColor:(ShapeColor)c{
fillColor = c;
}
-(void)setBounds:(ShapeRect)b{
bounds = b;
}
-(void)draw{
NSLog(@"drawing a Rectangle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
@end
//Egg类接口
@interface Egg : NSObject {
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds:(ShapeRect) bounds;
- (void) draw;
@end
//Egg类实现
@implementation Egg
-(void)setFillColor:(ShapeColor)c{
fillColor = c;
}
-(void)setBounds:(ShapeRect)b{
bounds = b;
}
-(void)draw{
NSLog(@"drawing a Egg at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
@end
//主函数
int main(int argc, const char * argv[]) {
//声明我们要绘制形状的数组
id shapes[3];
//设计红色的圆形
ShapeRect rect0 = {0,0,10,30};
shapes[0] = [Circle new];
[shapes[0] setBounds:rect0];
[shapes[0] setFillColor:kRedColor];
//设计绿色的矩形
ShapeRect rect1 = {30,40,50,60};
shapes[1] = [Rectangle new];
[shapes[1] setBounds:rect1];
[shapes[1] setFillColor:kGreenColor];
//设计蓝色的椭圆形
ShapeRect rect2 = {15,18,37,29};
shapes[2] = [Egg new];
[shapes[2] setBounds:rect2];
[shapes[2] setFillColor:kBlueColor];
//调用函数绘制形状
drawShapes (shapes,3);
return 0;
}
//绘制函数的实现
void drawShapes (id shapes[], int count) {
for (int i = 0; i < count; i++) {
id shape = shapes[i];
[shape draw];
}
}
//返回颜色函数的实现
NSString *colorName (ShapeColor colorName){
switch (colorName) {
case kRedColor:
return @"red";
break;
case kGreenColor:
return @"green";
break;
case kBlueColor:
return @"blue";
break;
default:
break;
}
}
//运行结果
2018-10-02 16:49:29.290177-0700 图像[504:7489] drawing a Circle at (0,0,10,30) in red
2018-10-02 16:49:29.290497-0700 图像[504:7489] drawing a Rectangle at (30,40,50,60) in green
2018-10-02 16:49:29.290509-0700 图像[504:7489] drawing a Egg at (15,18,37,29) in blue
Program ended with exit code: 0
可能的报错以及处理方法

处理方法
当需要绘制新的图形时,只需要创建一个新的类,避免了过程式编程的麻烦
3.有关术语
- 类:表示对象类型的结构体,对象通过它的类来获取自身的各种信息,建议首字母大写
- 对象:是一种包含值和指向其类的隐藏指针的结构体,首字母通常不需要大写
- 实例:对象的另一种称呼
- 消息:是对象可以执行的操作,用于通知对象去做什么
- 方法:为响应消息而运行的代码
- 方法调度:OC的一种机制,用于推测执行什么方法以响应某个特定的消息
- 接口:类为对象提供的特性描述
- 实现:使接口能正常实现的代码
4.Objective-C语言中的oop
-
4.1.@interface部分
用于定义类的公共接口
创建特定类的对象之前,OC编译器需要一些有关该类的信息,尤其是对象的数据成员及其提供的功能
@interface Circle : NSObject {//@interface Circle告诉编译器这是新类的接口
@private//Circle类对象需要的各种数据成员
ShapeColor fillColor;
ShapeRect bounds;
}
//方法声明
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds:(ShapeRect) bounds;
- (void) draw;
@end//告诉编译器,完成了Circle类的声明
对象方法:-(返回值)方法名:(参数类型)参数
对于冒号,方法使用参数才需要冒号,否则不需要
方法调用:[对象 方法:实参];
-
4.2.@implementation部分
真正使对象能够运行的代码
@implementation Circle//@implementation是一个编译器指令,表明你将为某个类提供代码
//方法的实现
-(void)setFillColor:(ShapeColor)c{//参数不能再用fillColor,不然我们会覆盖fillColor实例变量,并且编译器会生成警告
fillColor = c;
}
-(void)setBounds:(ShapeRect)b{//参数不能再用bounds,不然我们会覆盖bounds实例变量,并且编译器会生成警告
bounds = b;
}
-(void)draw{
NSLog(@"drawing a Circle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
@end
在实际生活中,我们必须区分参数名称和实例变量的名称
-
4.3.实例化对象
创建一个新的对象,需要向相应的类发送new消息
int main(int argc, const char * argv[]) {
//声明我们要绘制形状的数组
id shapes[3];
//设计红色的圆形
ShapeRect rect0 = {0,0,10,30};
shapes[0] = [Circle new];//创建对象
[shapes[0] setBounds:rect0];
[shapes[0] setFillColor:kRedColor];
//设计绿色的矩形
ShapeRect rect1 = {30,40,50,60};
shapes[1] = [Rectangle new];//创建对象
[shapes[1] setBounds:rect1];
[shapes[1] setFillColor:kGreenColor];
//设计蓝色的椭圆形
ShapeRect rect2 = {15,18,37,29};
shapes[2] = [Egg new];//创建对象
[shapes[2] setBounds:rect2];
[shapes[2] setFillColor:kBlueColor];
//调用函数绘制形状
drawShapes (shapes,3);
return 0;
}
id:表示的是标识符,是一种泛型,可以引用任何类型的对象,对象是一种包含代码的struct结构体,因此id实际上是一个指向结构体的指针
-
扩展OC程序
添加绘制三角形的功能
@interface Triangle : NSObject {//@interface Triangle告诉编译器这是新类的接口
@private//Triangle类对象需要的各种数据成员
ShapeColor fillColor;
ShapeRect bounds;
}
//方法声明
- (void) setFillColor:(ShapeColor) fillColor;
- (void) setBounds:(ShapeRect) bounds;
- (void) draw;
@end//告诉编译器,完成了Circle类的声明
@implementation Triangle//@implementation是一个编译器指令,表明你将为某个类提供代码
//方法的实现
-(void)setFillColor:(ShapeColor)c{//参数不能再用fillColor,不然我们会覆盖fillColor实例变量,并且编译器会生成警告
fillColor = c;
}
-(void)setBounds:(ShapeRect)b{//参数不能再用bounds,不然我们会覆盖bounds实例变量,并且编译器会生成警告
bounds = b;
}
-(void)draw{
NSLog(@"drawing a Triangle at (%d,%d,%d,%d) in %@",bounds.x,bounds.y,bounds.width,bounds.height,colorName(fillColor));
}
@end