年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1761|回复: 0

[项目经验] OC在block内部定义block并递归

[复制链接]
  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

    发表于 2016-3-1 12:02:24 | 显示全部楼层 |阅读模式
    1、如何定义block:
    格式为:[返回值] (^block名称)(形参类型1,形参类型2) = ^(形参1,形参2){ // code}
    例如:NSString *(^myBlock)(int, NSString*) = ^(int i, NSString *text){ return @"sian"}
    2、应用场景
    2.1、使用FMDB框架查询数据,如果需要模糊查询时如果查询结果为空,需要修改查询值再次查询;
    2.2、例如现在有一张城市名称、城市编码的数据库表,数据库中的城市名称如:北京、长沙等;
    2.3、用户在查询时有可能输入的是“北京市”,还有一些自治区县名称都特别长,而在数据库中有可能是简写的;
    2.4、SQL语句中使用like进行模糊查询只能是查询关键字是结果的一部分才可行,如果查询关键字大于结果值是无法查询到的;
    2.5、如果数据库中是北京市,使用“北京”去like查询是可以查询到北京市的,反过来则不行;
    2.6、基本想法是如果like查询为空,将关键字长度减1去掉最后一个字再次查询,直到返回查询结果或关键字被减至0再返回;
    2.6、如数据库中存在北京,使用“北京市”去like查询,结果为空则将北京市修改为“北京”再查询,如果返回为空再修改为“北”查询...
    3、要实现上述需要,FMDB中加载数据后进行查询是通过block实现的[queue inDatabase:^(FMDatabase *db) {// code}
    4、比较简单的方法是递归整个方法来实现,但多次递进后,在回归时会有多次返回值,不利于结果处理;
    5、在block中再定义block本身没有什么问题,局部可当做是一个外部整体,但block内部的block又是一个局部;
    6、如果内部block需要调用block中的变量需要加__block前缀进行修饰,但block内部的block需要递归该block本身则容易绕晕;
    7、这里的关键在于block需要递归调用block本身,那么该block在定义的时候该如何修饰自己?,这是关键!
    8、如果不修饰则block本身在定义完之后即会被释放掉,递归时出现野指针错误!
    9、使用__block修改,则block内部再调用本身,会出现循环引用造成内存泄漏!
    10、比较好的办法是使用static修改,定义为静态变量,在递归结束后再将该block指针赋值为空,个人感觉比较理想。

    相关代码示例:
    [Objective-C] 纯文本查看 复制代码
    /// 根据城市名称模糊查询城市及编码
    + (NSMutableDictionary *)getCityCodeWithCityName:(NSString *)cityName
    {
        // 如果城市为空则直接返回空
        if (cityName.length == 0) return nil;
        // 定义block变量返回结果
        __block NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        // 加载数据库表文件及操作队列
        NSString *path = [SAMainBundle pathForResource:@"SACityCode" ofType:@"db"];
        FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
        [queue inDatabase:^(FMDatabase *db) {
    
            __block FMResultSet *ret = nil;     // 在block内部定义一个block变量给内部block使用
            static void (^check)(NSString *);   // 定义一个block块,block内部会递归,不加修饰变量会被提前释放而出现野指针错误,加__block修饰会循环引用
            
            check = ^(NSString *city){
                NSString *sql = [NSString stringWithFormat:@"SELECT * FROM city WHERE city_name LIKE '%@%%'", city];
                FMResultSet *set = [db executeQuery:sql];
                if (set.next){ ret = set; return;}                  // 如果查询到结果则直接跳出
                if (city.length > 0) check([city deleteLastChar]);  // 将查询值删除末尾字再递归
            };
            check(cityName);
            // 如果ret不为空则表明递归查询有结果
            if (ret != nil){
                NSString *cityName = [ret stringForColumn:@"city_name"];
                NSString *cityCode = [ret stringForColumn:@"city_code"];
                [dict setObject:cityName key:@"city_name"];
                [dict setObject:cityCode key:@"city_code"];
            }
            [ret close];
            check = nil;
        }];
        return dict;
    }

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    手机版|小黑屋|Archiver|iOS开发笔记 ( 湘ICP备14010846号 )

    GMT+8, 2024-5-2 23:35 , Processed in 0.044932 second(s), 18 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表