信号量dispatch

    xiaoxiao2025-10-06  1

    我为什么要用信号量? 因为一个需求。

    需求介绍

    这是一个很常见的需求:项目中的业务接口请求的时候需要Token验证。我们最简化这个需求就是:两个请求,请求1成功返回所需参数之后,才能开始请求2。

    一个很容易想到的做法就是:

    - (void)getToken {     //以上请求的设置忽略     NSURLSessionDataTask *task = [mySession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {         if (data) {             NSLog(@"get Token"); //拿到token,传给request请求做参数             [self request:token];         }else{             NSLog(@"token error:%@",error.description);         }      }];     [task resume]; } - (void)request:(NSString *)params {     //请求的设置忽略     NSURLSessionDataTask *task = [mySession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {         if (data) {             NSLog(@"request success");         }else{             NSLog(@"request error:%@----",error.description);         }     }];     [task resume]; }

    这种做法是最容易想到的,但是缺点也是很明显的。获取token的方法与业务层的请求紧密混合在一起了,而且很不容易分离,这会导致你的网络管理类的请求方法变得臃肿。

    所以,下面我要用信号量使得token跟业务层的request完成分离开,使代码逻辑更清晰。

    dispatch_semaphore 介绍

    dispatch_semaphore只有三个方法:

    //创建信号量 dispatch_semaphore_create //发送信号量 dispatch_semaphore_signal //等待信号量 dispatch_semaphore_wait

    执行dispatch_semaphore_create 会根据传入的long型参数创建对应数目的信号量;执行 dispatch_semaphore_signal 会增加一个信号量;执行dispatch_semaphore_wait 则会减少一个信号量,如果信号量是0,就会根据传入的等待时间来等待。

    这样一解释,不知道你有没有醍醐灌顶。对于上面的需求,我们在请求token的时候创建信号量为0,成功的话发送信号量,在业务层请求前永久等待信号即可。

    看代码:

    //请求的按钮点击 - (IBAction)buttonPress:(UIButton *)sender { //创建信号量     dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);     [self getToken:semaphore]; //此时的信号量为0,只有token请求成功发送信号量之后,才会往下执行[self request]方法,否则会一直等下去;     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);     [self request]; } - (void)getToken:(dispatch_semaphore_t)semaphore {     //以上请求的设置忽略     NSURLSessionDataTask *task = [mySession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {         if (data) {             NSLog(@"get Token"); //成功拿到token,发送信号量:             dispatch_semaphore_signal(semaphore);         }else{             NSLog(@"token error:%@",error.description);         }      }];     [task resume]; }

    思路理顺了吧~让我们来跑一下程序: 哎呀~卡住了!。。。

    是的,因为我们设置了永久等待,所以token请求异步去请求,在当前线程信号量是0,就不会往下执行了,会一直这样卡下去,该怎么解决呢?没错,用异步嘛~

    再来代码:

    - (IBAction)buttonPress:(UIButton *)sender { //创建一个并行队列     dispatch_queue_t queque = dispatch_queue_create("GoyakodCreated", DISPATCH_QUEUE_CONCURRENT);     //异步执行     dispatch_async(queque, ^{         dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);         [self getToken:semaphore];         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);         [self request];     });          NSLog(@"main thread"); }

    再跑一下程序,看控制台打印信息:

    如果你还不放心可以多试几次,看看是不是token每次都在request之前。

    总结

    我们之所以要这样做,其实只有一个目的就是让代码清晰,这样获取Token的方法可以单独提出一个类,判断token是否过期等逻辑就不会跟业务请求混在一起了,毕竟真正项目运用的时候网络请求类要比demo复杂得多。

    最后

    demo 地址

    转载请注明原文地址: https://ju.6miu.com/read-1302895.html
    最新回复(0)