Functions 函数
和变量、控制流、条件一样、函数也是现代编程语言的基本组成部分。他可以使我们在应用中重复利用一块代码,对于代码的组织和维护是很有必要的。您将在IOS和OS X的框架中发现大量的例子。
像其他的基础元素一样,Object-C的函数也是建立在C语言函数之上的。这章我们将介绍C语言最重要的方面,包括基本语法、声明和实现、变量生命周期以及函数库的注意事项。
Basic Syntax 基本语法
C语言的函数有四部分组成:返回值、函数名、参数以及相关的代码块。定义之后,您可以通过传递必要的参数,调用函数,执行相关的代码。
比如,下面的例子,定义一个getRandomInteger函数,接受两个int类型的参数,返回一个int类型的返回值。在函数内部,我们通过minimum 和maximum 参数获取传递给函数的值,通过reture关键字返回计算的值。在main函数中,我们可以通过传递10和-10作为参数,调用函数。
// main.m
import <Foundation/Foundation.h>
int getRandomInteger(int minimum, int maximum) {
return arc4random_uniform((maximum - minimum) + 1) + minimum;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int randomNumber = getRandomInteger(-10, 10);
NSLog(@"Selected a random number between -10 and 10: %d",
randomNumber);
}
return 0;
}
内置的函数arc4random_uniform,可以返回从0到您传递参数的一个随机数。
函数可以使用指针引用作为函数的返回值和参数,这就意味着您可以同样的方式使用Object-C的对象。比如,在main中添加如下代码。
// main.m
import <Foundation/Foundation.h>
NSString *getRandomMake(NSArray *makes) {
int maximum = (int)[makes count];
int randomIndex = arc4random_uniform(maximum);
return makes[randomIndex];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *makes = @[@"Honda", @"Ford", @"Nissan", @"Porsche"];
NSLog(@"Selected a %@", getRandomMake(makes));
}
return 0;
}
getRandomMake 接受NSArray类型的对象作为参数,返回NSString类型的对象。注意,它同样使用*语法,声明指针变量。
Declarations vs. Implementations 声明 vs 实现
在使用函数之前,您必须定义函数。如果您定义getRandomMake函数在main函数之后,当您调用这个函数时,编译器是找不到这个函数的。这样强加了一个限制,不利于大型项目有的组织。为了解决这个问题,C语言将函数的声明和实现分开了。
函数的声明是告诉编译器,函数的输入和输出是什么样的。通过提供返回数据类型和参数,编译器确认您是否正确使用函数,但是不知道函数具体的实现。相应的函数实现实在声明的基础上添加了一块代码。
下面的代码声明了函数getRandomMake ,所以您可以在main中调用,而且函数还没有被实现。注意,函数申明中只需要参数的类型,参数的名字是可以省略的。
// main.m
import <Foundation/Foundation.h>
// Declaration
NSString *getRandomMake(NSArray *);
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *makes = @[@"Honda", @"Ford", @"Nissan", @"Porsche"];
NSLog(@"Selected a %@", getRandomMake(makes));
}
return 0;
}
// Implementation
NSString *getRandomMake(NSArray *makes) {
int maximum = (int)[makes count];
int randomIndex = arc4random_uniform(maximum);
return makes[randomIndex];
}
正如您将要看到的,分离函数的声明和实现,对于组织打的项目是很有用的。
The Static Keyword Static 关键字
static 关键字可以改变函数和变量的可见性。不幸的是,它的作用和他所使用的位置有关。本小节常用的两个static用法。
Static Functions static 函数
通常函数时全局可见的。也就是说,一旦您定义了一个函数,您在其他任何地方都可以调用这个函数。static关键字可以限制函数只在当前文件中可见,这样对于创建一个私有的函数和防止命名冲突很有用。
下面是怎样创建一个static函数的例子,如果您在另外一个文件声明和实现函数,您在main函数中是不能调用函数的。注意static在函数的声明和实现中都使用了。
// Static function declaration
static int getRandomInteger(int, int);
// Static function implementation
static int getRandomInteger(int minimum, int maximum) {
return arc4random_uniform((maximum - minimum) + 1) + minimum;
}
Static Local Variables 静态本地变量
声明在函数中的变量,每次执行的时候都会被初始化。这是一个很直观的默认行为,也就是说函数会忘记,您调用它多少次。但是,如果您使用static声明本地变量,函数可以记住不同调用的值。
比如,下面的变量currentCount ,从来都不会被重新初始化。我们不在main中定义技术变量,我们可以使用countByTwo计数。
// main.m
#import <Foundation/Foundation.h>
int countByTwo() {
static int currentCount = 0;
currentCount += 2;
return currentCount;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"%d", countByTwo()); // 2
NSLog(@"%d", countByTwo()); // 4
NSLog(@"%d", countByTwo()); // 6
}
return 0;
}
不想上节介绍的static函数,static不影响变量的可见性。所以本地变量只能在函数中访问。
Function Libraries 函数库
Objec-C不支持命名空间,为了防止命名的冲突,我们在函数名之前加上前缀,比如NSMakeRange和CGImageCreate。
当您创建自己的函数时,函数的声明和实现,在不同的文件中。这样使引入头文件的文件不必担心函数的实现。比如CarUtilities 的头文件如下所示:
// CarUtilities.h
#import <Foundation/Foundation.h>
NSString *CUGetRandomMake(NSArray *makes);
NSString *CUGetRandomModel(NSArray *models);
NSString *CUGetRandomMakeAndModel(NSDictionary *makesAndModels);
相应的实现文件定义函数的具体实现。因为文件不支持引入函数实现,您可以使用static关键字,创建一个私有的函数。
// CarUtilities.m
#import "CarUtilities.h"
// Private function declaration
static id getRandomItemFromArray(NSArray *anArray);
// Public function implementations
NSString *CUGetRandomMake(NSArray *makes) {
return getRandomItemFromArray(makes);
}
NSString *CUGetRandomModel(NSArray *models) {
return getRandomItemFromArray(models);
}
NSString *CUGetRandomMakeAndModel(NSDictionary *makesAndModels) {
NSArray *makes = [makesAndModels allKeys];
NSString *randomMake = CUGetRandomMake(makes);
NSArray *models = makesAndModels[randomMake];
NSString *randomModel = CUGetRandomModel(models);
return [randomMake stringByAppendingFormat:@" %@", randomModel];
}
// Private function implementation
static id getRandomItemFromArray(NSArray *anArray) {
int maximum = (int)[anArray count];
int randomIndex = arc4random_uniform(maximum);
return anArray[randomIndex];
}
现在,您可以引入头文件,调用函数,如果定义在同一个文件中。如果您试图在main中调用getRandomItemFromArray ,将会导致一个编译错误。
// main.m
import <Foundation/Foundation.h>
import "CarUtilities.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSDictionary *makesAndModels = @{
@"Ford": @[@"Explorer", @"F-150"],
@"Honda": @[@"Accord", @"Civic", @"Pilot"],
@"Nissan": @[@"370Z", @"Altima", @"Versa"],
@"Porsche": @[@"911 Turbo", @"Boxster", @"Cayman S"]
};
NSString *randomCar = CUGetRandomMakeAndModel(makesAndModels);
NSLog(@"Selected a %@", randomCar);
}
return 0;
}
Summary 总结
本章用函数介绍,结束了C语言基础讲解。我们学习了声明函数和实现函数,改变他们的可见性,使记住本地变量,和组织大的函数库。
Cocoa 和Cocoa Touch 中大部分功能都分装的类中。现在我们已经做好了,学习Object-C面向对象特性了,下章我们将学习类的定义、对象初始化、属性的设置已经方法的调用。