Object-C 语言是C语言的超集,意思就是咱们可以将两种语言写在同一个源码文件里。java
Object-C语言结构的核心是创建在C语言之上的。因此在学习语言的高级特性以前,掌握C语言基础是很是重要的。objective-c
这个模块为C语言提供一个简洁的概述。咱们将讨论关于凝视、变量、算数运算符、控制流、简单的数据结构、指针。编程
这些概念是咱们讨论Object-C面向对象特性的基础。数组
在C语言中有两种方式可以提供凝视。行内凝视。以双斜线開始,到本行结束。markdown
块凝视,可以跨越多行,但是必须在 /* 和 */ 之间。
比方:数据结构
// This is an inline comment
/* This is a block comment. It can span multiple lines. */
因为编译器会忽略凝视,这样就可以让咱们在代码的旁边加入额外的信息。这样可以帮助咱们解释一些easy误解的代码,Object-C代码基本是自解释的。因此您不是很是需要在IOS 和 OS X 应用加入太多的凝视。框架
变量是一个容器。他可以存储不一样的值。dom
在C语言中,变量类型是静态的,意思就是您必须清楚的声明。您想存储什么类型的值。声明变量的语法为: ,给变量赋值用=操做符。ide
假设您想将一个变量转化成还有一个类型,您可以在变量前加入括号,括号里加入新类型。函数
所有的都在如下的代码中演示了。声明了一个 odometer 变量,可以存储double类型的变量。 (int)odometer 的声明将转化odometer 存储的值 为一个int类型。假设您将代码粘贴在main.m文件里。执行程序。
您将在输出面板中看到NSLog()中的消息。
// main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
double odometer = 9200.8;
int odometerAsInteger = (int)odometer;
NSLog(@"You've driven %.1f miles", odometer); // 9200.8
NSLog(@"You've driven %d miles", odometerAsInteger); // 9200
}
return 0;
}
像double和int同样。C语言定义了很是多原生的数据类型。
一个完整的列表可以在原生模块中找到。而且上面用到的the %.1f 和 %d 格式化符号也有解释。
常量修饰符是告诉编译器,这个变量是不能被改动的。比方定义一个变量叫pi,假设您试图改动它,将会致使编译器报错。
double const pi = 3.14159;
pi = 42001.0; // Compiler error
这个通常是用在函数的參数中。告诉函数的调用者,他们可以假设传递给函数的參数是不会被改动的。
咱们熟悉的+, -, *, /符号是用来作主要的算数运算符。模运算符(%)被用来返回整数相除的余数。
如下是演示:
NSLog(@"6 + 2 = %d", 6 + 2); // 8
NSLog(@"6 - 2 = %d", 6 - 2); // 4
NSLog(@"6 * 2 = %d", 6 * 2); // 12
NSLog(@"6 / 2 = %d", 6 / 2); // 3
NSLog(@"6 %% 2 = %d", 6 % 2); // 0
当涉及到浮点数或者整数操做时,要特别的当心。具体信息请看整数相除。
当您使用循环时,经常遇到++ 或者–操做符。他是一个从变量中减一或者加一的简易的符号。
int i = 0;
NSLog(@"%d", i); // 0
i++;
NSLog(@"%d", i); // 1
i++;
NSLog(@"%d", i); // 2
像其它的语言同样C语言也提供了标注的if声明。他的主要的语法,以及一个用于描写叙述逻辑运算符的表,例如如下所看到的:
int modelYear = 1990;
if (modelYear < 1967) {
NSLog(@"That car is an antique!!!");
} else if (modelYear <= 1991) {
NSLog(@"That car is a classic!");
} else if (modelYear == 2013) {
NSLog(@"That's a brand new car!");
} else {
NSLog(@"There's nothing special about that car.");
}
Operator Description
a == b Equal to
a != b Not equal to
a > b Greater than
a >= b Greater than or equal to
a < b Less than
a <= b Less than or equal to
!a Logical negation
a && b Logical and
a || b Logical or
C语言也提供了 switch 声明,但是參数仅仅能是整数,不能是浮点数、指针或者其它的Object-C对象。与if条件语句相比較,至关的不灵活。
// Switch statements (only work with integral types)
switch (modelYear) {
case 1987:
NSLog(@"Your car is from 1987.");
break;
case 1988:
NSLog(@"Your car is from 1988.");
break;
case 1989:
case 1990:
NSLog(@"Your car is from 1989 or 1990.");
break;
default:
NSLog(@"I have no idea when your car was made.");
break;
}
while 和 for 循环可以迭代一些值。相关的break 和continue可以对应使退出循环,或者跳过一个迭代
int modelYear = 1990;
// While loops
int i = 0;
while (i<5) {
if (i == 3) {
NSLog(@"Aborting the while-loop");
break;
}
NSLog(@"Current year: %d", modelYear + i);
i++;
}
// For loops
for (int i=0; i<5; i++) {
if (i == 3) {
NSLog(@"Skipping a for-loop iteration");
continue;
}
NSLog(@"Current year: %d", modelYear + i);
}
现在是合适的时间介绍for-in循环,然而这并不是C语言的。这个称为高速枚举语法,因为相比传统的for和while循序。它是一种更加有效的迭代Object-C集合的方法。比方NSSet 和NSArray 。
// For-in loops ("Fast-enumeration," specific to Objective-C)
NSArray *models = @[@"Ford", @"Honda", @"Nissan", @"Porsche"];
for (id model in models) {
NSLog(@"%@", model);
}
Macros are a low-level way to define symbolic constants and space-saving abbreviations. The #define directive maps a macro name to an expansion, which is an arbitrary sequence of characters. Before the compiler tries to parse the code, the preprocessor replaces all occurrences of the macro name with its expansion. In other words, it’s a straightforward search-and-replace:
宏指令是一个定义符号常量和别名的底层方法。
// main.m
import
int main(int argc, const char * argv[]) {
@autoreleasepool {
double angle = PI / 2; // 1.570795
NSLog(@"%f", RAD_TO_DEG(angle)); // 90.0
}
return 0;
}
This code snippet demonstrates the two types of C macros: object-like macros (PI) and function-like macros (RAD_TO_DEG(radians)). The only difference is that the latter is smart enough to accept arguments and alter their expansions accordingly.
Typedef可以使咱们定义一个新的数据类型或者又一次定义一个已经存在的数据类型。
如下演示一个无符号字符的typeof定义,咱们可以使用ColorComponent 就像咱们是用char、int、double和其它内建数据类型。
// main.m
import
int main(int argc, const char * argv[]) {
@autoreleasepool {
ColorComponent red = 255;
ColorComponent green = 160;
ColorComponent blue = 0;
NSLog(@"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
red, green, blue);
}
return 0;
}
typedef 一般被用做将struct或者enum转化成更加方便的数据类型。这个被演示在如下两个段落。
struct 像一个简单的、原生的C对象。它可以让你聚合一些变量在一个比較复杂的数据结构,但是它不提供面向对象编程的特性,比方方法。比方,如下的代码片断使用struct聚合了组成RGB的元素。
注意。咱们经过typeof。可以经过更加有意义的名字获取。
// main.m
import <Foundation/Foundation.h>
typedef struct {
unsigned char red;
unsigned char green;
unsigned char blue;
} Color;
int main(int argc, const char * argv[]) {
@autoreleasepool {
Color carColor = {255, 160, 0};
NSLog(@"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
carColor.red, carColor.green, carColor.blue);
}
return 0;
}
咱们使用了{255, 160, 0}的初始化语法,来初始化新的carColor 结构体。这个复制的顺序和咱们定义struct的顺序同样。
而且咱们可以经过点语法获取每一个域。
enum 关键字被用于定义枚举类型,他是一个相关常量的集合。
像struct,经过typedef定义个更加有描写叙述性的名字。
// main.m
import <Foundation/Foundation.h>
typedef enum {
FORD,
HONDA,
NISSAN,
PORSCHE
} CarModel;
int main(int argc, const char * argv[]) {
@autoreleasepool {
CarModel myCar = NISSAN;
switch (myCar) {
case FORD:
case PORSCHE:
NSLog(@"You like Western cars?"); break; case HONDA: case NISSAN: NSLog(@"You like Japanese cars?"); break; default: break; } } return 0; }
觉得myCar 变量被定义为CarModel 类型。因此他仅仅能存储四种类型的枚举成员: FORD, HONDA, NISSAN, and PORSCHE。
定义这些在一个枚举类型中,比使用字符串表明各类CarModel更加的可靠。
Cocoa 框架使用大量的枚举定义常量。比方NSSearchPathDirectory 定义OS X使用的 标准文件夹路径。
Ry’s Cocoa的教程。数据存储章节中提供了大量的样例。
因为Object-C是C语言的超级,它就可以訪问C语言中的数组。Foundation 提供的NSArray 和 NSMutableArray 比C 语言的数组更加的方便好用。
然而,对性能要求比較高的环境,C语言数组仍是很是实用的。
int years[4] = {1968, 1970, 1989, 1999};
years[0] = 1967;
for (int i=0; i<4; i++) {
NSLog(@"The year at index %d is: %d", i, years[i]); }
years[4] 声明分配了可以存储四个int值得连续内存空间。
咱们使用 {1968, …}的初始化语法初始化了数组,咱们可以经过传递偏移在方括号里获取数组的元素值。
指针是一个内存地址的引用。
指针删除了一个抽象层、是你可以看到。数值是如何存储的。
这样需要两个工具。
引用操做符可以返回变量内存地址。
这样你就可以建立一个指针。
解引用操做符可以返回内存地址的存储内容。
如下演示了,如何申明、建立、解除指针。注意一个指针就像定义一个一般的变量。但是就是在变量以前加入了*。
int year = 1967; // Define a normal variable
int *pointer; // Declare a pointer that points to an int
pointer = &year; // Find the memory address of the variable
NSLog(@"%d", *pointer); // Dereference the address to get its value
*pointer = 1990; // Assign a new value to the memory address
NSLog(@"%d", year); // Access the value via the variable
指针图形化的表演示样例如如下:
上面的样例,指针仅仅是一个非必须的变量的抽象。他的实际的用处。你可以在附近移动指针。
尤为是遍历数组,一个连续的内存空间。比方线面,经过指针迭代数组元素。
char model[5] = {'H', 'o', 'n', 'd', 'a'};
char *modelPointer = &model[0];
for (int i=0; i<5; i++) {
NSLog(@"Value at memory address %p is %c", modelPointer, *modelPointer); modelPointer++; } NSLog(@"The first letter is %c", *(modelPointer - 5));
当咱们使用指针。++操做符将移动指针到下一个地址,咱们可以输出地址经过含有%p修饰符NSLog。
相同,–操做符被用做减指针到以前的地址。
如上所看到的,您可以訪问相对当前地址的不论什么地址。
空指针是一个特殊的指针,不指向不论什么地址。
C语言中仅仅有一个空指针。他的类型是NULL 宏。主要表示变量为空,变量不能有一个正常的值。比方所看到的,经过空指正置空一个指针。
int year = 1967;
int *pointer = &year;
NSLog(@"%d", *pointer); // Do something with the value
pointer = NULL; // Then invalidate it
咱们表示year 为空变量,可以经过设置为0实现,但是,对于year也是一个正常的值,而不是缺乏值。
void 类型的指针是一个通用类型。它可以指向不论什么地址。所以,咱们需要将void类型的指针转化成非void类型的指针。比方, (int *)申明将指正转化成int类型的指正。
int year = 1967;
void *genericPointer = &year;
int *intPointer = (int *)genericPointer;
NSLog(@"%d", *intPointer);
void 类型指正提供了很是多的灵活性。比方NSString 类定义例如如下方法。将C数组转化成Object-C的字符串。
- (id)initWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding
bytes 參数指向C数组的内存第一个地址。length參数执行读取多少字节,encoding 參数如何解析字节。使用void类型的指针,这样bytes參数可以是不论什么字符数组。
这是一些背景知识。但是您平常的Object-C开发中并不需要。咱们必须理解。Object-C中的每一个对象都是经过指针引用的。
比方,NSString 类型变量必须存储一个指针,而不是一个主要的变量。
NSString *model = @"Honda";
空指针在Object-C和C中是不同的,在C中使用NULL。Object-C定义可本身的宏,nil,他是空。重要经验是,在引用Object-C对象指针中使用nil。而对于C指针使用NULL。
NSString *anObject; // An Objective-C object
anObject = NULL; // This will work
anObject = nil; // But this is preferred
int *aPointer; // A plain old C pointer
aPointer = nil; // Don't do this
aPointer = NULL; // Do this instead
整个Object-C语法都是和指正相关的。
定义了一对象指针以后,您基本就忘记了他是一个指针,因为使用和其它的变量同样。
咱们将经过本教程的大量样例理解清楚。
本章主要解说C语言的基础。
主要是想让你们熟悉变量、条件、循环、结构体、枚举、和指针。这些工具是构成不论什么Object-C程序的基础。
Object-C依赖C的这些基础结构。而且给与直接加入C++代码的选择。为了告诉编译器,编译的是C、C++或者Object-C,您可以将源码的文件扩展名改动为.mm。
这个独特的语言特征。打开了整个C/C++的大门,这是对于Object-C开发人员最大的恩惠。比方。您在开发IOS游戏,发现本身需要一个物理引擎,你可以使用注明的Box2D 包。不需要额外的工做。
下一章咱们将经过学习函数,结束C语言的学习。在这以后,咱们已经准备好学习Object-C类、方法、协议和其它面向对象的内容。