因为Cocoa是基于OOP概念的,并且Objective-C也是一种面向对象的编程语言,所以在学习Objective-C的时候必然频繁讨论OOP概念。
0x01 什么叫间接?
间接(Indirection)是一个OOP的关键概念,可以理解为“在代码中通过指针间接获取某个值,而不是直接获取”。
0x02 变量与间接
基本变量就是间接的一种实际应用,例如使用变量表示循环次数,如果想改变循环次数,只需修改代码中的变量值即可:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
int count = 100; //变量count起到间接的作用
NSLog (@"The numbers from 1 to %d:", count);
for (int i = 1; i <= count; i++)
NSLog (@"%d\n", i);
return 0;
}
0x03 使用文件名的间接
在程序中内置的词组串列表
假设有一个程序可以统计并输出多个词组串的长度:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
const char *words[4] = {
"Joe-Bob \"Handyman\" Brown",
"Jacksonville \"Sly\" Murphy",
"Shinara Bain",
"George \"Guitar\" Books" }; //词组串列表
int wordCount = 4; //需统计的数目
for (int i = 0; i < wordCount; i++)
NSLog (@"%s is %lu characters long", words[i], strlen(words[i]));
return 0;
}
在这个程序中,如果我们经常要修改词组串列表,就必须频繁改动程序,还要同步修改需统计的数目变量。万一单词数目众多,我们就必须进行大量的修改工作,还得十分谨慎保证不犯错。从面向对象的角度来讲,这样是不科学的。
把词组串列表放入文本文件
所以,我们可以用另外一种思维构造程序:
将所有单词都移动到代码之外的某个文本文件中,按一定规则组织文件结构,如一行一个名字,这也是一种间接。
先构造一个文本文件(word.txt),并存放在tmp目录中:
Joe-Bob "Handyman" Brown
Jacksonville "Sly" Murphy
Shinara Bain
George "Guitar" Books
再构造一个程序读取该文本文件:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
FILE *wordFile = fopen ("/tmp/words.txt", "r"); //tmp是Unix的临时目录,计算机重启时会被清空
char word[100];
while (fgets(word, 100, wordFile))
{
//把换行符替换成空字符
word[strlen(word) - 1] = '\0';
NSLog (@"%s is %lu characters long", word, strlen(word));
}
fclose (wordFile);
return 0;
}
采用这种方案之后,我们可以在文本文件中随时改变词组串的组合,而不必修改程序,避免源代码遭到破坏。但是这个方案仍然不够便利,文件路径没法由使用者指定,万一文件不在程序指定的位置,我们同样必须修改源代码。
用命令行参数指定文件名
所以,我们要做进一步改进:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
if (argc == 1) //验证用户是否提供了路径名作为启动参数,argc的值至少为1,如果用户提供了路径名,则argc必然大于1
{
NSLog (@"you need to provide a file name");
return 1; // argc = 1时表示没有文件可读取
}
//如果argc > 1,则按路径读取文件
FILE *wordFile = fopen (argv[1], "r");
char word[100];
while (fgets(word, 100, wordFile))
{
//把换行符替换成空字符
word[strlen(word) - 1] = '\0';
NSLog (@"%s is %lu characters long", word, strlen(word));
}
fclose (wordFile);
return 0;
}
其中,我们通过查看argv数组来获知词组串文件的路径。argv[0]存放着程序名,argv[1]保存着用户提供的文件名。
《C/C++语言体系中的main()函数参数argc, argv是什么?》
如果在终端应用中运行此程序,那么在命令行中指定文件名则如下所示:
$ ./Word-Length-4 /tmp/words.txt
Joe-Bob "Handyman" Brown is 24 characters long
Jacksonville "Sly" Murphy is 25 characters long
Shinara Bain is 12 characters long
George "Guitar" Books is 21 characters long
关于在调试运行前设置文件路径,请参考: