"OC基础"这个分类的文章是我在自学Stephen G.Kochan的《Objective-C程序设计第6版》过程中的笔记。
1、 函数和方法的区别?
(1)、方法包含在类内部,而函数不用包含在类里面;
(2)、方法就是函数的一种。
2、数组中某个元素的读法,比如grades [5]读作“grades sub 5”。
3、关于C语言的数组元素的初始化:
(1)、直接列出所有元素的值,比如:
int integer[5] = {1, 2, 3, 4, 5};
char letters[5] = {‘a’, ‘b’, ‘c’, ‘d’, ‘e’};
(2)、如果只指定了较少的初始化值,那么只会初始化等量的元素,比如:
float s_data[500] = {100.0, 143.00, 45.50};
那么数组中的前三个元素会被初始化成100.0, 143.00, 45.50,其他元素被设为0;
(3)、可以直接指定某个元素的值,比如:
int x = 1233;
int a[] = {[9]=x+1, [2]=3};
在这个例子中,直接指定了编号为9的元素的值为1234,指定了编号为2的值为3。同时这个数组没有指定大小,编译器会根据数组内容里出现了[9]将数组的大小定为10。
4、关于C语言的字符数组:
如果有一个字符数组定义如下:
char word[] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘!’, ‘\0’};
这个数组的大小会自动被定为7,‘\0’是终止空字符,有了这个符号之后,可以使用NSLog方法打印这个数组,打印成字符串的格式,语句如下:
NSLog(@’%s’, word);
’%s’表示NSLog会持续地显示字符,直到遇见‘\0’才终止。而后面要打印的内容只需要写上数组的名称,不需要方括号。
5、关于C语言的多维数组:
(1)、多维数组的声明方法如下:
int M[4][5];
这个语句定义了一个4行5列总共20个元素的多维数组,每一个元素都包含一个整型值;
(2)、多维数组的初始化可以直接列出数组的所有元素:
int M[2][4] = {
{10,5,6,3},
{34,23,1,20}
}
这里需要注意,除了最后一行,每一行结束都要使用逗号分开;
(3)、如果要列出数组所有元素的方法来初始化多维数组,其实可以不用花括号:
int M[2][4] = {10,5,6,3,34,23,1,20}
编译器会自动匹配;
(4)、也可以不用初始化整个多维数组:
int M[2][4]{
{1,2},
{3,4}
}
这样会初始化每行的前两个元素,其余值都会被设为0。这种情况下一定要使用内层花括号。
6、如果没有声明函数的返回类型,编译器会假设返回类型为整型;如果方法没有指定返回类型,编译器会假设返回类型为id类型;
7、如果函数的参数数目不确定,那么可以使用省略号来做形参,比如:
void NSLog(NSString *format, ...);
那么在参数NSString *format后面,就可以是任意数目的附加参数。注意省略号只有三个点。
这里指的是NSLog函数的定义,NSLog函数确实是参数数目不确定的,有时输出一个值,有时输出多个值。
8、静态函数:
默认情况下,函数是外部的。即是所有和该函数链接在一起的文件中的所有函数和方法都可以调用这个函数。如果使用static关键字将其定义为静态函数,可以限制它的作用域:
static int gcd(int u, int v){
...
}
静态函数则只有和这个函数在同一个文件的函数或者方法可以访问它。
9、如果要向某个函数传递数组里的第i个元素作为参数,那么直接使用以下方式即可:
fx( xArray[i] )
如果要传递整个数组作为参数,那么只需要在调用写出数组的名称,不需要任何下标:
fx( xArray )
10、如果在函数或方法中改变了作为参数的数组元素的值,那么这个变化会确实地影响到这个数组本身,不论函数或方法是否已调用完成。因为函数或方法使用数组做参数时,传递给形参的并不是整个数组本身,而是传递一个指针,它指向数组所在的地址。所以对形参所做的更改其实都是指向原始数组本身的修改。
11、块的基本模板:
void (^callName) (int) = ^(int n) {
NSLog(@”%i”, n);
};
需要注意的地方如下:
(1)、第一个void是这个块的返回类型;
(2)、callName是这个块赋给的变量名称,在定义了这个块之后,使用callName(2);这样的格式就可以调用这个块;
(3)、等号前的(int)是这个块的参数列表,等号后的(int n)是形参,同时形参也有“^”这个符号;
(4)、块的最后要以分号结尾。
(5)、调用(^callName)的语句应该是:“callName();”,注意是有括号的。
12、块定义在函数或者方法内部,能够访问在函数或方法内块之外的任何变量。块能够访问但是不能改变这些变量的值,除非使用在块前面含有两个下划线的块修改器。
13、块能够作为参数传递给方法或函数。
14、一个例子:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
autoreleasepool {
int foo = 10;
void (^printFoo) (void) = ^(void){
NSLog(@”Foo is %i”, foo);
};
foo = 15;
printFoo();
}
return 0;
}
这个例子的输出结果是foo=10。首先把foo赋值为10,然后定义了块(^printFoo),最后再把foo赋值为15。这时候调用(^printFoo),发现出来的结果foo还是10。
说明块内包含的变量的值在块定义的时候就确定了,块在使用到块外部的变量的时候会将变量复制一份来使用,所以在定义完块后再去变动变量的值不会影响到块内的变量的值。一般来说,在块内部不允许修改变量的值,编译器会报错。
15、一个例子:
#import <Foundation/Foundation.h>
int main(int arvc, char *arvg[]){
autoreleasepool{
__block int foo = 10; //此处为(1)
void (^printFoo) (void) = ^(void){
NSLog(@”foo = %i”, foo);
foo = 20; //此处为(2)
}
foo = 15;
printFoo();
NSLog(@”foo = %i”, foo);
}
return 0;
}
首先这个例子如果在(1)这个地方不插入“__block”的话,那么在(2)这个地方就会报错,因为在块内部不允许修改变量的值,如果要修改的话必须在定义这个变量的时候使用在块前面含有两个下划线的块修改器。
这个例子的输出结果是:
foo = 15
foo = 20
由于定义了“__block”,那么foo的值的修改就会影响到块了。首先定义foo的值为10,程序经过块的时候,foo被修改为20,然后在块完结之后,foo被指定为了15。这时候调用printFoo,出来的值就是foo=15,同时在打印为foo=15之后,快内部的代码继续走下去,把foo置为了20。最后使用NSLog函数打印出来的就是foo=20了。
另外需要注意,“__block”是由两个下划线和block组成的,它们之间没有空格。
16、一个简单的结构:
struct date{
int month;
int day;
int year;
};
关于这个结构:
(1)、定义结构必须以分号结尾;(和块一样)
(2)、这个结构的类型是“struct date”而不是“date”,应该这样声明这个类型的变量:
struct date today;
(3)、设置或读取today里面的day的值为1的话,要使用点运算符:
today.day = 1;
17、结构的初始化方式:
(1)、直接列出所有元素的值:
struct date today = {2, 1, 2015};
(2)、使用点运算符可以任意顺序或者部分赋值来初始化:
struct date today = { .year=2015, .month=2};
18、可以使用typedef来使结构的类型名称更简略,比如定义了某个结构类型struct CGPoint,那么可以:
typedef struct CGPoint CGPoint;
即是用CGPoint来替代struct CGPoint,那么定义结构的时候就可以用以下语句:
CGPoint myPoint;
这里要注意,在声明结构的时候不需要使用*号;在声明对象的时候(比如Fraction *frac)才需要用到*号。声明了结构之后,就可以使用点运算符来操作结构内部的元素了。