【block作为函数参数的应用案例之一 Objective-C语言】

一、例如,有一个数组:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
char *countries[] =
{
“Nepal”,
“Cambodia”,
“Afghanistan”,
“China”,
“Singapore”,
“Bangladesh”,
“India”,
“Maldives”,
“South Korea”,
“Bhutan”,
“Japan”,
“Sikkim”,
“Sri Lanka”,
“Burma”,
“North Korea”,
“Laos”,
“Malaysia”,
“Indonesia”,
“Turkey”,
“Mongolia”,
“Pakistan”,
“Philippines”,
“Vietnam”,
“Palestine”
};
return 0;
}

1.这是1个字符串数组,每一个元素都是char *类型的字符串

2.现在我要干嘛呢,我要写1个类,数组类,给这个数组类提供1个方法,将1个字符串数组进行排序

3.来1个类,叫做TestArray,这个类,到目前为止,是不是只要提供1个方法就可以了,排序的方法,对谁排序,对字符串数组排序,要不要返回值,不要,因为数组是地址传递,我把数组传进来以后,我里面一改顺序,是不是外面也跟着改了吧,名字sort,有没有参数,有,是不是应该把那个数组传过来啊,数组的类型,char 星 数组:char *[]

- (void)sortWithCountries:(char *[])countries;

我们说过,这是我们类的方法,参数的类型写在小括弧里面,参数的名字写在外面

在TestArray.m文件里实现1下,现在这个方法要做的事情非常简单,就是对这个数组进行排序,这个countries参数是不是就是数组啊,怎么排序,是不是冒泡排序或者选择排序啊,都可以,你喜欢哪个就用哪个,例如冒泡排序:

- (void)sortWithCountries:(char *[])countries

{

int len = sizeof(countries) / sizeof(char *);

for(int i=0;i<len;i++)

}

把一个数组作为函数的参数的时候,结果就会丢掉这个数组的长度,所以这个sizeof(countries)是几,是8啊

所以你能不能这样去算长度:int len = sizeof(countries) / sizeof(char *);

不能,不能怎么办

是不是要在函数外面算好,然后传进来啊,

- (void)sortWithCountries:(char *[])countries andLength:(int)len;

在TestArray.m文件中实现1把:

- (void)sortWithCountries:(char *[])countries andLength:(int)len{

//

}

然后再使用冒泡排序:

- (void)sortWithCountries:(char *[])countries andLength:(int)len{

for(int i = 0 ; i < len - 1 ; i++)

{

for(int j = 0 ; j < len - 1 - i ; j++){

//下标为j的和下标为j+1的进行比较

//j j+1

//countries[j] countries[j+1]

//只要小于或者大于我就调换位置吧

//那么怎么比较呢

//是不是strcmp啊

//那我是不是应该把那个String.h引进来啊

int res = strcmp(countries[j],countries[j+1]);

if ( res > 0 )

//如果res大于0,说明什么,说明j是不是比j+1大,那我是不是要把j和j+1调换位置啊

if(res > 0 )

{

char *temp = countries[j];

countries[j] = countries[j+1];

countries[j+1] = temp;

}

}

}

}

在main.m文件中试一下

CZArray *arr = [CZArray new];

[arr sortWithCountries:countries andLength:sizeof(countries)/8];

return 0;

}

//这个时候我就可以算数组的长度了,计算数组长度的时候,直接除以8就可以了,因为每一个元素是个char指针,而char指针占8个字节,我是不是直接除以8就可以了

//然后打印出来试一下

这个时候,这个方法执行完了以后,这个数组已经排好序了吧

for(int i = 0;i < sizeof(countries)/8;i++)

{

NSLog(@“%s”,countries[i]);

}

//你发现,是不是就排序好了啊

二、我们现在的需求是,写1个数组类,为这个数组类提供1个方法,为1个国家字符串数组进行排序

1.第一个问题,现在是按字母顺序来排序的,谁让你用字母顺序来排序的,万一产品经理要我们用字符串的长度来排呢,或者用国家的面积来排呢,或者用国家的经济实力来排呢,所以这个时候,这个方法这么写,写死了

int res = strcmp(countries[j], countries[j+1]);

这里比较j和j+1的时候

最开始的做法:比较j和j+1这两个字符串,我们直接比较的字母顺序,也就是ASCII码

但是这么写的话,就写死了

现在,重点就是比较j和j+1,这两个字符串的大小,我们现在比的是它们的ASCII码,也就是字母顺序,这时候调用者的需求是,这个比较规则可不可以由调用者自己说了算

想法:比较这两个字符串的大小,不要方法的内部自己写代码去比,

因为不管写什么都是写死的,

j和j+1这两个字符串,我让调用者自己写1段代码来比

所以这个地方需要执行调用者写的1段代码,来比较j和j+1的大小

首先,应该想个办法,让调用者把代码传到这儿来执行吧

怎么传,block

让调用者把代码放在block里面,传到这儿来执行

大家思考一下,那个block的签名应该怎样做的,有没有返回值,肯定有,要比较两个字符串的大小,你得告诉我谁大谁小吧,你得告诉我第一个是否比第二个大吧,所以返回值什么类型的,BOOL类型

BOOL (^)

写1个block来存储1段代码,这段代码做的事情:比较j 和 j+1 两个字符串的大小,返回结果。

所以这段代码有没有返回值,有,BOOL类型的,你告诉我第一个是否比第二个大

BOOL (^取个名字)

BOOL (^compareBlock)()

有没有参数,有,几个参数,两个参数,什么类型的,是不是字符串啊!

BOOL (^compareBlock)(char *country1,char *country2);

所以,我就希望调用者写这么1段代码传给我,这段代码做的事情做什么事情,比较country1和country2的大小,传到我这儿来执行,就可以了

所以,这时候我是不是应该给它加个参数啊,加个block,那么这个block怎么写呢

- (void)sortWithCountries:(char *[])countries andLength:(int)len andCompareBlock:();

这个compareBlock是不是应该写上刚才我们那个符合要求的代码段吧

这个block怎么写呢

- (void)sortWithCountries:(char *[])countries andLength:(int)len andCompareBlock:();

第一个,我们刚刚说过,我们这个方法的小括弧里面写上参数类型啊,变量名、参数名写在外面啊

- (void)sortWithCountries:(char *[])countries andLength:(int)len andCompareBlock:(BOOL (^)(char *country1,char *country2))compareBlock;

返回值,BOOL类型,小括号,尖尖,尖尖里面需要写变量名字吗,不需要,我们说过啊,名字写在小括号外面啊,再来个小括号,两个参数,最后来一个名字compareBlock

(BOOL (^)(char *country1,char *country2))compareBlock;

这个时候你看啊,我们说过嘛,函数的小括号里面,是不是应该写上参数的类型啊,参数的名字写在小括号外面吧,本来我的block的名字应该写在这个地方对不对,就是尖尖右边,(BOOL (^),但我们是方法,名字写在外面就可以了

如果你感到蒙圈怎么办,是不是用typedef把它简化一下啊

typedef BOOL (^NewType)(char *country1,char *country2);

- (void)sortWithCountries:(char *[])countries andLength:(int)len andCompareBlock:(NewType)compareBlock;

这个时候,比较j和j+1这两个字符串的大小,就不要自己去比了

int res = strcmp(countries[j],countries[j+1]);

谁去比,是不是让block里面的代码去比啊,compareBlock里面的代码去比,而这个block里面的代码要谁写,是不是让调用者自己写啊

上面那句代码,换成

compareBlock(countries[j],countries[j+1]);

因为这个block有两个参数嘛,两个字符串嘛,那我就把这两个字符串传过去啊

返回值是什么类型的,BOOL类型的,拿BOOL类型的变量接一下

BOOL res = compareBlock(countries[j],countries[j+1]);

if(res == YES)

如果res == YES,就说明什么呢,就说明j比j+1大,那我就干嘛呢,我就交换位置

char *temp = countries[j];

countries[j] = countries[j+1];

countries[j+1] = temp;

但是有个问题啊,j和j+1到底怎么比的,是不是这个block里面的代码块来决定的啊,compareBlock,这里面的代码块来决定的啊,而这个block代码块是谁写的,是不是调用者一会儿要传进来的啊

我们在main.m文件里试一下:

肯定不是这样写了吧:

TestArray *arr = [TestArray new];

[arr sortWithCountries:countries andLength:sizeof(countries)/8];

因为加了参数了吧

[arr sortWithCountries:countries andLength:sizeof(countries)/8 andCompareBlock:^BOOL (char *country1,char *country2)compareBlock];

第一个,把这个数组传进去,第二个,把数组的长度传进去,第三个,传什么?

是不是传1个代码段进去啊

回车,回车以后是不是自动生成这个block代码段啊

[arr sortWithCountries:countries andLength:sizeof(countries)/8 andCompareBlock:^BOOL (char *country1,char *country2){

code;

}];

也就是说,这里面,你只要写代码就可以了,你判断country1是不是比country2大就可以了

这个时候,怎么比,是比ASCII码,还是比字符串的长度,随便比,你想怎么比,你就写代码就可以了

如果你想比ASCII码,你就country1和country2去比ASCII码就可以了,如果你想比字符串的长度,你就写上比字符串的长度就可以了

如果我们想比字符串的长度,就这样写:

[arr sortWithCountries:countries andLength:sizeof(countries)/8 andCompareBlock:^BOOL (char *country1,char *country2){

int res = (int)strlen(country1) - (int)strlen(country2);//这是取到第一个字符串的长度,再减去第二个字符串的长度,我一减,假如等于res吧

当然它这个返回值是什么类型的,是size_t类型的是不是,那我把它强转一下,强转成int类型

如果res大于0了,说明什么,是不是说明第一个字符串的长度比第二个字符串的长度大啊,就return YES,否则我就return NO

if(res > 0 )

{

return YES;

}

return NO;

}];

TestArray.m里面的方法,写成如下这样:

for(int i = 0 ; i < len -1 ; i++)
{
for(int j = 0 ; j < len - 1 - i ; j++)
{
int res = compareBlock(countries[j],countries[j+1]);
if(res > 0 )
{
char *temp = countries[j];
countries[j] = countries[j+1];
countries[j+1] = temp;
}
}
}

运行一下,字符串就以长度从小到大来排序了

如果另一个人来调用这个方法,他不想以长度来排序,他想以字母顺序来排,怎么办,是不是只要改一下block里面的代码就可以了

[arr sortWithCountries:countries andLength:sizeof(countries)/8 andCompareBlock:^BOOL(char *country1, char *country2) {
int res = strcmp(country1,country2);
return res > 0 ;
}];

strcmp(country1,country2)这个比的是ASCII码,对不对,拿到1个结果,int res

return res > 0;

如果res大于0,返回的就是YES,否则就是NO

有一个很有意思的问题,我TestArray里面的方法有没有改过,没有改过,我调用两次这个方法,结果不一样,它们排序的标准是不一样的

三、总结

1.什么时候block可以作为方法、函数的参数

当方法的内部需要去执行一段代码,需要执行一个功能,例如咱们这个例子里,

BOOL res = compareBlock(countries[j],countries[j+1]);

这个地方是不是要去比较j和j+1的大小

但是这个功能具体的实现,到底怎么比的,函数的内部不确定

那么这个时候,就使用block,让调用者将这个功能的具体实现传递进来

猜你喜欢

转载自blog.csdn.net/madoca/article/details/126861277