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


    一、例如,有一个数组:

    #import
    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

    }

    把一个数组作为函数的参数的时候,结果就会丢掉这个数组的长度,所以这个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文件中试一下

    TestArray *arr = [TestArray 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,让调用者将这个功能的具体实现传递进来

  • 相关阅读:
    全栈经验总结(不间断更新)
    如何将dwg文件转成kml文件
    【npm】npm私有库的使用-绑定
    React组件渲染和更新的过程
    Element Plus el-form表单自定义插槽如何使用
    ps命令实用例子
    安卓使用android studio跨进程通信之AIDL
    网络编程套接字,Linux下实现echo服务器和客户端
    用来检查 CUDA、Conda 和 PyTorch 的版本的python文件
    uniapp——授权报错,选择合适的基础库
  • 原文地址:https://blog.csdn.net/madoca/article/details/126861277