从java转向Objective-C思想转变总结
之前一直学习的是java,javaweb,最近接触的是安卓的开发,假期看了一些关于Objective-C的内容
,由于家里没有网络不能即时发布博文和大家分享了~
从之前学习的java语法到现在接触的Objective-C有很多不同之处,例如:Objective-C没有垃圾回收器,却含有保留/释放方法和自动释放池。必要时,也可以在Objective-C程序中进行垃圾回收。
Java接口与Objective-C正式协议类似,因为都需要实现一组方法。Java具有抽象类,但Objective-C没有。Java具有类变量,但Objective-C中,可以使用文件范围内的全局变量并为它们提供对应的访问器。Objective-C的公共和私有方法的形式比较松散。在Objective-C中,对象支持的任何方法都可以被调用,即使它们没有以任何外部形式出现(例如头文件中)。Java允许声明final类,阻止更改其中的任何子类,而Objective-C则与此相反,允许在运行时向任何类添加方法。
Objective-C中类的实现方式可以分成两个文件,头文件和自身的实现文件。但并不是一定要这样划分(例如某些小的私有类),这在本书的某些代码中意境有所反映。头文件(带有.h扩展名)保留类的公开信息,例如使用此类的代码讲使用的任何新的枚举、类型、结构,以及代码。其他代码段使用预处理器(#import)导入该文件。Java中缺少C预处理器。C预处理器是一种文本替换工具,它能在C、Objective-C和C++源代码进行编译器之前,先对它们进行自动处理,以#开头的指令表示一个预处理器命令。C预处理器是一个功能非常强大但又危险的工具。很多编程人员都认为java中缺少预处理器是一个良好的特性。
在java中,几乎所有错误都是通过一场来处理的。而在Objcective-C中,错误处理的方式取决于所使用的API。Unix
API通常会返回值-1和一个全局错误编号(error),以设置某个特定的错误,Cocoa API通常仅在编程人员出现或无法清除时才抛出异常。Objective-C语言提供的异常处理特性与java及C++类似,采用@try、@catch、和@finally结构。
在Objective-C中,空(零)对象采用nil表示,可以向nil对象发送消息,而不必担心出现NullPointerException异常。向nil对象发送的消息代表停止操作指令,因此,不必检查发送的消息是否为NULL。
在Objective-C中,通过使用类别向现有类中添加方法,可以改变类的行为。 Objective-C中没有类似于final的类。因为编译器需要知道超类定义的对象的大小,所以任何类只要包含子类头文件,就可以把它设置为子类。
实际上,相对于java而言,在Objective-C中很少使用子类化行为。因为,通过类别和动态运行时机制,可以想任何对象发送任何消息,可以将某些功能放到含有较少功能的类中,也可以将功能呢放到最有意义的类中。例如:可以在NSString上加入类别来添加反转字符串或删除所有空格等特征,然后可以在任何NSString类中调用该方法,无论调用来自何处。当然,你也可以使用自己的字符串子类来提供那些特性。
一般来说,只有当创建某个全新的对象(位于对象层次结构的顶部),或者需要从根本上改变某个对象的行为,或者由于类不能实现某个功能而需要使用子类时,才需要在Cocoa中设置子类,例如:Cocoa使用NSView类机构用户界面组件,却无法实现它的dramRect:方法。因此,需要试这NSView的子类并重写dramRect:方法来绘制视图。但对其他大多数对象,通常采用委托和数据源的方式。由于Objective-C可以想任何对象发送任何消息,对象不必含有特定的子类或遵从特定的接口,这样,单个类就可以成为任意个不同对象的委托和数据源。
因为类别中意境声明了数据源和委托方法,因此,不必实现所有的数据源和委托方法,在Objective-C中,Cocoa编程很少使用空存根方法,某些方法会在嵌入式对象中调用相同的方法来使编译器能够顺利底适应一种正式协议。
当然,功能越强,责任越大。Objective-C采用手动保留、释放和自动释放的内存管理系统,这样容易产生一些棘手的内存错误,在其他类中添加类别是一种功能强大的工作机制,但如果随意滥用,会降低代码的可读性,导致其他人无法理解。另外,Objective-C是以C为基础的,因此,可以使用C语言的所有特性,同事包括使用预处理器可能带来的危险,并可能出现与指针相关的内存管理错误。
最简单的Objective-C程序与基础语法解析
你可能见过C语言版本的经典“Hello World”程序,该程序可输出“Hello
World”或类似的简短语句。“Hello World”通常是C语言编程初学者要学习的第一个程序。我们将继承此优良传统,便携一个类似的程序,这里称为“Hello
Objective-C”
解构Hello Objective-C程序
hello Objective-C.m内容如下;
#import
int main(int argc, const char *argv[])
{
NSLog (@”hello, Objective-C!”);
Return (0);
} |
Xcode的.m扩展名表示文件含有Objective-C代码,应由Objective-C编译器处理。C编译器处理名称以.c结尾的文件,而C++编译器处理.cpp文件。在Xcode中,所有这些编译工作全由GCC(GNU
Compiler Collection,GNU编译器集合)处理,这个编译器能够理解C语言的全部3哥变体。
如果了解普通的C语言,那么你应该很熟悉.m主文件中包含的两行代码:main()声明和末尾的return(0)语句。请记住,Objective-C本质上就是C语言,它用来声明main()和返回值的语法和C语言是一样的。其他代码看上去与正规的C语言有些许差别,例如:这个陌生的#import是什么?
Objective-C刚诞生的时候,扩展名.m代表message,指的是Objective-C的一个主要特性。
#import,与C语言一样,Objective-C使用头文件来包含元素声明,这些元素包括结构体、符号常量、函数原型等。C语言使用#include语句通知编译器应在头文件中查询定义。在Objective-C程序中也可使用#include来实现这个目的。但你可能永远不会那么做,而会像下面这样使用#import:
#import <Foundation/Foundation.h>
#imiport是GCC编译器提供的,Xcode在编译 Objective-C、C和C++程序时都会使用它。#import可保证头文件只被包含一次,而不论此命令实际上在那个文件中出现了多少次。(在C语言中,程序员通常使用基于#ifdef命令的方案来避免一个文件包含另一个文件,而后者又包含第一个文件的情况。而在Objective-C中,程序员使用#import实现这个功能。)
#import <foundation/Foundation.h>语句告诉编译器查看Foundation框架中的Foundation.h头文件。
浅析Froundation框架基础
什么是框架?框架是一种聚集在一个单元的部件集合,包含头文件、库、图像、声音文件等。苹果公司将Cocoa、Carbon、QuickTime和OpenGL等技术作为框架集提供。Cocoa的组成部分有Foundation和Application
Kit(也称为AppKit)框架。还有一个支持框架的套件,包含Core Animation和Core Image,这为Cocoa增添了多种精彩功能。
Foundation框架处理的是用户界面之下的层(layer)中的特性,例如数据结构和通信机制。要想称为Cocoa权威专家,还需要精通Cocoa的Application
Kit,它包含Cocoa的高级特性:用户界面元素、打印、颜色和声音管理、AppleScript支持等。
每个框架都是一个重要的技术集合,通常包含数十个甚至上百个头文件。每个矿建都有一个主头文件,它包含了所有框架的各个头文件。通过使用#import导入主头文件,可以使用所有框架的特性。
Foundation框架的文投建占用了近1MB的磁盘存储空间,包含一万四千多行代码,涵盖一百多哥文件。使用#import<Foundation/Foundation.h>包含主头文件,就能够获得整个集合。也许你认为辛苦地读取每个文件的全部文本会耗去编译器很多时间,但是Xcode非常聪明:它会使用预编译头文件(一种经过压缩的)摘要形式的头文件),在通过#import导入这种文件时,加载速度会非常快。
如果你想知道Foundation框架包含哪些头文件,可以查看其Headers目录(/System/Library/Frameworks/Foudation.framework/Headers/)。如果只是浏览文件,而不删除或更改它们,就不会造成任何破坏。
NSLog()和@”字符串”
使用#import导入了Foundation框架的主头文件后,就可以开始利用Cocoa特性编写代码了。Hello
Objective-C中的第一行实际代码使用了NSLog()代码,如下所示:
NSLog(@”hello , Objective-C !”); |
此代码可向控制台输出”hello , Objective-C !”。如果你使用过C语言,那么一定遇到过printf(),而NSLog()这个Cocoa函数的作用和printf()很相似。
和Printf()一样,NSLog()接受一个字符串作为其第一个参数,该字符串可包含格式说明符(如%d)。此函数还可以接受匹配格式说明符的其他参数,printf()可在打印之前将这些参数插入到作为第一个参数的字符串中。
Objective-C只是增加了一点“特殊调料”的C语言,所以可以用printf()代替NSLog()。但我们建议使用NSLog(),因为它添加了特性,例如世界戳、日期戳和自动附加换行符(’\n’)等。
你也许需不太理解函数名NSLog()。这里的“NS”是什么意思?其实,Cocoa对其所有函数、常量和类型名称都添加了“NS”前缀。这个前缀告诉你函数来自Cocoa而不是其他工具包。
两个不同食物使用相同表示服时会导致名称冲突,而前缀可以预防这个大问题。如果Cocoa将此寒食命名为Log(),那么这个名称很可能和一些程序员创建的Log()函数冲突。当包含Log()的程序和Cocoa一起创建时,Xcode会警告Log()被多次定义,将产生糟糕的结果。
前缀为何是“NS”而不是“Cocoa”?“NS”前缀的来历要追随至此工具包还被称为NextSTEP,而且是NeXT
software公司(前NeXT公司,于1996年被苹果公司收购)产品的时候,但品故宫公司没有破坏为NextSTEP便携的代码的兼容性,继续使用“NS”前缀,由此可见,“NS”是历史遗存了。
Cocoa已占用了“NS”前缀,所以很明显,不应该再为自建的变量或函数名称添加前缀“NS”。否则处理代码的阅读器会发生混乱,它们会认为你创建的内容实际上属于Cocoa。同样,假如将来苹果公司为Cocoa添加了一个函数,碰巧和你创建的名称相同,那么你的代码可能会出现问题。由于没有集中管理的前缀注册表,所以可以任意选择前缀。很多人使用他们的姓名首字母或公司名称作为前缀,为了使我们的例子更简单,本书中不为代码添加前缀。
看下面NSLog()语句:
NSLog(@”Hello , Objective-C !”); |
你是否注意到了字符串前的@符号?这是Objective-C在标准C语言基础上添加的特性之一。双引号中的字符串前有一个@符号,这表示引用的字符串应该作为Cocoa的NSString元素来处理。
什么是NSString元素?去掉“NS”前缀后,就可以看到熟悉的术语“String”。你已经知道字符串就是一串字符,所以你一定能猜到NSString就是Cocoa中的一串字符。
NSString元素有许多打包的特性,Cocoa在需要字符串时可随时使用它们。下面是一些NSString功能。
告知其长度;
将自身与其他字符串比较;
将自身转换为整型值或浮点值。
还有许多功能是使用C风格字符串无法实现的。
观察这些字符串
一个易犯的错误是将C风格字符串(而不是专门的NSString的@“字符串”元素)传递给MSLog(),如果是这样,编译器会给出警告:
main.m:46: warning:passing arg 1 of ‘NSlog’ fromincompatible
pointer type
如果要运行这个程序,它可能会崩溃,要捕捉这样的问题,可以让Xcode总是将警报作为错误来处理,方法是,选择Xcode
Groups & Files列表顶端的项目,选择File—Get Info命令,选择Build选项卡,在搜索区输入“error”,然后勾选Treat
Warningsas Error复选框。
数据类型知识点总结
布尔类型
许多语言都有布尔(Boolean)类型,当然这是个专用术语,指的是存储真值和假值的变量。Objective-C也不例外。
C语言拥有布尔数据类型bool,它具有true值和false值。Objective-C提供了相似的类型BOOL,它具有YES值和NO值。顺便提一下,Objective-C的BOOL类型比C语言的bool类型早诞生十多年。这两种不同的布尔类型可以在同一个程序中共存,但在便携Cocoa代码时要使用BOOL。
Objective-C中的BOOL实际上是一种对带符号的字符类型(signed char)的定义(typedef),它使用8位存储空间。YES定义为1,NO定义为0(使用#define)。
Objective-C并不讲BOOL作为仅能保存YES或NO值的真正的布尔类型来处理。编译器将BOOL认做8位二进制数,YES或NO只是一种约定,这引发一个小问题:如果不小心讲一个长于1字节的整型值(例如short或int值)赋给一个BOOL变量,那么只有低位字节会用作BOOL值,假设该低位字节刚好为0(例如8960,携程十六进制为0x2300),BOOL值将会是0,即NO值。
数据类型和常量
整型int:表示方法:
十进制:格式符符号:%i(long:%Li)
八进制:首位为0,其后为0~7之间的数,格式符为:%o(long:%Lo)(不带0),%#o(带0)
十六进制:首位为:0x(大小皆可),其后为0~9、A~F(10~15)组合。格式符为:%x(无0x),%#x(带0x)
浮点float:转换字符:%f。1.7*104= 1.7e4,1.7*10-4=1.7e-4,E或e皆可。科学技术法格式符:%e。%g:允许NSLog确定使用常用的浮点计数法还是使用科学计数法来显示浮点。这一决定取决于指数的值:如果该值小于-4或大于5,采用%e(科学计数法)表示,否则采用%f(浮点计数法)。
双精度double:格式符号:%f(long:%Lf),%e(long:%Le),%g(long:%Lg)同float一致。范围是float两倍。
字符型char:例如:‘a’。前面有@字符并且放在双引号中的字符串是NSString字符串对象。
字符常量‘\n’(换行符)是一个合法的字符常量,因为反斜杠符号是Objectiv-C系统中的特殊符号,实际上并不把它看成一个字符。换句话说,Objective-C编译器将字符’\n’看作单个字符,尽管它实际上由两个字符组成。格式符号:%c。
类、对象和方法解析
在Objective-C中,小写字母和大写字母是不同的,即区分大小写。
注释:单行注释://
块注释:/*……*/
注意:注释不能嵌套使用。
换行符:\n
输出操作:NSLog(@”内容”);
类、对象和方法
什么是对象?对象就是一个食物。把面向对象的程序设计看成一个事物,而且想对这个事物做些功过,这与C语言不同,C语言通常称作过渡性语言。在C语言中,通常是先考虑要做什么,然后才关注对象,这几乎总是与面向对象的思考过程相反。
程序在逻辑上分为3个部分:
@interface部分
用来描述类、类的数据成分以及类的方法;
@implementation部分
包括实现这些方法的实际代码
@program部分
包含实现程序预期目的的程序代码。
以上每个部分都是每个Objective-C程序的一部分,它们分别放到一个单独的文件中。
@interface部分,定义新类时,首先要通知Objective-C编译器这个类来自何处,就是说,必须命名它的父类。其次必须确定这个类对象要存储的数据的类型,必须描述类成员将包含的数据,我们把这些成员叫做实例变量。最后定义在处理该类的对象时将要用到的各种操作或方法的类型。这些工作都在程序中名为@interface的特殊部分内完成。格式类似于:
@interface NewClassName:ParentClassName
{
memberDeclarations;
}
methodDeclarations;
@end |
按照约定,类名以大写字母开头,尽管没有要求这么做。但这种约定能使其他人在阅读你的程序时,仅仅通过观察名称的第一个字母就能把类名和其他变量类型区分开来。
Objective-C的命名规则
名称必须以字母或下划线开头,之后可以是任何(大写或小写)字母、下划线或者0到9之间的数字组合。保留字不能作为变量名,任何对Objective-C编译器有特殊意义的名称都不能作为变量名使用。
Objectiv-C中的大写字母和小写字母是有区别的。在命名类时,类名要以大写字母开始;实例变量、对象以及方法的名称,通常以小写字母开始。为使程序具有可读性,名称中要用大写字母来表示新单词的开始。例如:
AddressBook—可能是一个类名
currentEntry—可能是一个对象
current_entry—一些程序员还使用下划线作为单词的分隔符。
addNewEntry—可能是一个方法名。
示例:如下@interface部分代码:
//------@interface section ------
@interface Fraction:NSObject
{
int numerator;
int denominator;
}
-(void) print;
-(void) setNumerator:(int) n;
-(void) setDenominator:(int) d;
@end
|
解读:新类(NewClassName)的名称为Fraction,其父类为NSObject。NSObject类在文件NSObject.h中定义,导入Foundation.h文件时在程序中自动包括这个类。
实例变量
memberDeclarations部分制定了哪些类型的数据将要存储到Fraction中,以及这些数据类型的名称。这部分放入自己的一组花括号中。对于Fraction类而言,声明表示Fraction对象有两个名为numerator和denominator的整型成员。这一部分声明的成员称为实例变量。
每次创建新对象时,将同时创建一组新的实例变量,而且是唯一的一组。如果拥有两个Fractions,一个为FracA,另一个为FracB,那么每个对象都有自己的一组实例变量。Objective-C系统会自动追踪这些实例变量。
-(void) print;
print方法的声明,应该位于接口文件中,用来显示内容的方法(C语言)。开头的负号(-)通知Objective-C编译器,这个方法是一个实例方法。其他唯一的选择是正号(+),它表示类方法。类方法是对类本身执行某些操作的方法,例如创建类的新实例。
实例方法对类的特定实例执行一些操作,例如设置值、检索值和显示值等。
返回值,声明新方法时,必须通过Objective-C编译器这个方法是否返回值,如果返回值,那么返回哪种类型的值。将返回类型放入开头的负号或正号之后的圆括号中,可完成这项工作。
例如:-(int)retrieveNumerator;
返回值为int类型,通过return返回。
如果方法无返回值,可用void类型表示:-(void) print;无需在方法结尾执行一条return语句或执行一条不带任何指定值的return语句:return;
方法的参数:
-(void)setNumerator:(int)n;
-(void)setDenominator:(int)d;
这两个方法都是不返回值的实例方法。每个方法都有一个整型参数,这是通过参数名前面的(int)指明的。就setNumerator来说,其参数名是n。这个名称可以是任意的,它是用来引用参数的方法名称。因此,setNumerator的声明指定向该方法传递一个名为n的整型参数,而且该方法没有要返回的值。
每个方法名都以冒号结束,这个冒号通知Objective-C编译器该方法期望看到一个参数。然后指定参数的类型,并将其放入一对圆括号中,这与为方法自身指定返回类型的方式十分相似。最后使用象征性的名称来确定方法所指定的参数。整个声明以一个分号结束:
如果方法接受一个参数,那么在引用该方法时在方法名之后附加一个冒号。
@implementation部分
@implementation部分包含声明在@interface部分的方法的实际代码。在@interface部分声明方法并在@implementation部分定义给出实际的代码。
格式如下:
@implementation
NewClassName
methodDefinitions;
@end
|
NewClassName表示的名称与@interface部分的类名相同。可以在父类的名称之后使用冒号,如同在@interface部分使用的冒号一样:
@implementation Fraction:NSObject
然而,它是可选的而且通常并不这样做。
@implementation部分中的methodDefinitions部分包含在@interface部分指定的每个方法的代码。与@interface部分类似,每种方法的定义首先指定方法(类或者实例)的类型、返回类型、参数及其类型。然而,我们并没有使用分号来结束该行,而是将之后的方法代码放入一对花括号中。如下:
//---@implementation section ---
@implementation Fraction
-(void) print
{
NSLog(@”%i/%i”,numerator,denominator);
}
-(void) setNumerator:(int) n
{
numerator =n;
}
@end |
Program部分:
包含解决特定问题的代码,如果有必要,它可以跨越多个文件,但必须在其中一个地方有一个名为main的例程。通常情况下,这是程序开始执行的地方。
//---program section ----
int main(int argc,char *argv[]){
Fraction *myFraction;
//Create an instance of a Fraction
myFraction = [Fraction alloc];
myFraction = [Fraction init];
//set fraction to 1/3
[myFraction setNumerator:1];
[myFraction setDenominator:3];
//Display the fraction using the print method
NSLog(@”the value of myFraction is:”);
[myFraction print];
[myFraction release];
return 0;
} |
在main中,使用以下程序行定义了一个名为myFraction的变量:
这个行表示myFraction是一个Fraction类型的对象,就是说,myFraction用于存储来自新的Fraction类变量。myFraction前面的星号(*)是必需的,从技术上,它实际表示myFraction是对Fraction的一个引用(或者指针)。
现在你拥有一个用于存储Fraction的对象,需要创建一个分数:
myFraction =[Fraction alloc]; |
alloc是allocate的缩写。因为要为新分数分配内存空间存储空间:
向新创建的Fraction类发送一条消息。你请求Fraction类使用alloc方法,但是你从未定义这个alloc方法,于是此方法是来自继承一个父类的。
将alloc消息发送给一个类时,便获得该类的新实例。返回值存储在变量myFraction中。Alloc方法保证对象的所有实例变量都编程初始状态。然而这并不意味着该对象进行了适当的初始化进而可以使用。在分配对象之后,还必须对其初始化。
通过如下语句完成:
myFraction = [myFraction init]; |
init方法用于初始化类的实例变量。
你正在将init消息发送给myFraction,即要在这里初始化一个特殊的Fraction对象,因此它没有发送给类,而是发送给类的一个实例对象:myFraction;
init方法也可以返回一个值,即被初始化的对象。将返回值存储到Fraction的变量myFraction中。
如下两行代码分配了类的新实例并做了初始化,这两条消息在Objective-C中特别茶盎见,通常组合到一起:
myFraction = [[Fraction alloc]init]; |
内部消息表达式:
分配一个新的Fraction实力对象并分配和初始化:
Fraction *myFraction=[[Fraction alloc] init]; |
这种编码的风格非常重要。例如分配自动释放池:
NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init]; |
此处将alloc消息发送给NSAutoreleasePool类,请求创建一个新实例,然后向新实例对象发送init消息以初始化该对象。
[myFraction setNumerator:1];把消息setNumerator发送给myFraction,提供一个值为1的参数。
类、对象、方法的总结:
类的声明:@interface 类名:父类名
{
常量、变量
}
方法:
-(返回值类型)方法名;
-(void)方法名:(参数类型)参数名;
负号代表实例方法,正号代表类方法;
方法的实现:@implementation类名
-(void)David
{
}
-(void)David:(int)n
{
} |
对象的使用:main(@Program)中,
//创建类的实例对象并分配内存、初始化
Car *car1 = [[Car alloc] init]; |
等同于: Car *car1 = [Car new];
方法的调用:
[实例对象 方法名];
[实例对象 方法名:参数值];
OOP的一个关键概念:间接
在编程行业有句老话,大意是:“只要多添加一个间接层,计算机科学中就没有解决不了的问题。”间接这个词的含义很简单——不在代码中直接使用某个值,而是使用指向该值的指针。下面是一个真是的例子:你可能不知道自己最喜欢的比萨饼店的电话号码,但你知道可以查阅字典号码薄来找到它,那么,使用电话号码薄就是一种间接的形式。
在编程时,可以利用多层间接,如编写一段代码来查询其他代码,而后者又可以访问另一层代码。你大概拨打过技术支持热线。你对支持员工说明了问题,他将你转接到能够处理此问题的具体部门。该部门员工又将你转接到下一级技术人员,他可帮你解决问题。如果你和我们一样,在这时发现自己拨打了错误的号码,那么你不得不转向另一部门寻求
帮助,这种推诿就是一种形式的间接。幸运的是,计算机的耐心是无限的,为了找到答案,能够接受多次差遣。
关键词:变量和间接
基本变量就是间接的一种实际应用。考虑下面这个输出数字1到5的小程序。
#import
int main(int argc, const char *argv[])
NSLog(@”Thenumbers from 1 to5:”);
int i;
for(i=1;i<=5;i++){
NSLog(0);
}//main |
假设你想更新这个程序,使其输出数字1到10,那么你需要更改两处代码:
NSLog(@”The numbers from 1 to10:”);
i=1;i<=10;i++ |
这样修改程序显然不需要太多技巧,你可以用简单的搜索替换操作来完成,而且只需改变两处。然而,在比较大的程序中,执行搜索和替换就麻烦多了,仅仅是将5替换为10,我们也必须小心:毫无疑问,有些情况下数字5是与此无关的,所以不应该改为10.
解决这个问题就是变量的目的。不必直接在代码中修改上限循环值(5或10),我们可以将这个歌数字放到变量中,于是添加一个间接曾,这样就能够解决问题。添加变量后,就是告诉程序“去查看名为count的变量,它会说明进行多少次该循环”,而不是“执行5次循环”。现在程序如下:
#import
int main(int argc, coust char *argv[])
{
int count =5;
NSLog(@”Thenumbers from 1 to %d:”, count);
Int I;
For(i=1;i<=count;i++){
NSLog(@”%d\n”, I );
} NSLog(@”Thenumbers from 1 to5:”);
return(0)
}//main |
通过添加变量,代码现在更加干净,并且更易于扩展。为了修改循环值,她们不必仔细查看程序中使用的每个数字5,以确定是否需要修改,而是只需修改count变量就可获得期望的结果。
使用文件名的间接
文件是另一种间接的示例。这个重要程序是新web2.0公司站点Length-o-words.com的关键技术。
#import
int main(int argc, coust char *argv[])
{
coust char*words[4] = { “aardvark”, “abacus”, “allude”, “zygote” };
int wordCount =4;
int i;
for( i=0; i< wordCount; i++){
NSLog( @”%sis %d characters long “, words[ I ], strlen(words[i]));
}
return(0);
}//main<!DOCTYPE HTML> |
for循环可在任何时候确定要处理words数组中的哪个单词。循环内的NSLog()函数使用%S格式说明符来输出单词。之所以使用%S,是因为words是C字符串数组,而不是@”NSString”对昂。%d格式说明符取strlen90函数的整数值,此函数计算字符串的长度,并输出单词本身及其长度。
|