【iOS 入门】对比android handler学习NSOpration
iOS 和 android 都有主线程的概念。这点十分相似。
android 中 更新UI 通过 handler looper messagequee来处理。iOS有类似机制。
通过NSOpration 是其中一种。
现在对学习 NSOpration
java中开起线程有多种方法 Callable、Thread、 Executor线程池发起等。
iOS同样有NSThread GCD NSOpration等。
本文先只讨论 NSOpration
理解方式:NSOpration 接近于 java线程池。也就是Executor
NSInvocationOperation: 单个任务线程执行 通过SEL去执行一个方法。(SEL 理解为 方法指针)。
例子:
- (void)viewDidLoad { [super viewDidLoad]; // 可以传递一个 NSObject 给operation的操作方法 NSDictionary *dict = [NSDictionary dictionaryWithObject:@"value1" forKey:@"key1"]; NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationSelector:) object:dict]; NSLog(@"start before"); [op start]; NSLog(@"start after"); } // NSInvocationOperation 操作执行的方法 - (void)operationSelector:(NSDictionary *)dict { // 接收传进来的dict NSLog(@"dictValue = %@", [dict valueForKey:@"key1"]); sleep(10); // 加个睡眠模仿耗时操作 NSLog(@"currentThread = %@", [NSThread currentThread]); NSLog(@"mainThread = %@", [NSThread mainThread]); }
这个代码类似于:
不同之处是SEL可以指向任何方法,executor需要的是Runnable对象。
NSBlockOperation 其实 NSInvocationOperation 是一样的。
SEL 换成 block而矣。 其实两者都是方法指针。真正目的都是执行一段代码块。
addExecutionBlock 可以加入多个block 并且是异步执行的。
例子:
- (void)viewDidLoad { [super viewDidLoad]; NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"BlockOperation 1 begin"); sleep(10); // 加个睡眠模仿耗时操作 NSLog(@"BlockOperation 1 currentThread = %@", [NSThread currentThread]); NSLog(@"BlockOperation 1 mainThread = %@", [NSThread mainThread]); NSLog(@"BlockOperation 1 end"); }]; [op addExecutionBlock:^{ NSLog(@"BlockOperation 2 begin"); sleep(10); NSLog(@"BlockOperation 2 currentThread = %@", [NSThread currentThread]); NSLog(@"BlockOperation 2 mainThread = %@", [NSThread mainThread]); NSLog(@"BlockOperation 2 end"); }]; [op addExecutionBlock:^{ NSLog(@"BlockOperation 3 begin"); sleep(10); NSLog(@"BlockOperation 3 currentThread = %@", [NSThread currentThread]); NSLog(@"BlockOperation 3 mainThread = %@", [NSThread mainThread]); NSLog(@"BlockOperation 3 end"); }]; NSLog(@"start before"); [op start]; NSLog(@"start after"); }
接下去应该是: NSOperationQueue
可以看出是operation队列。但不能直观理解是FIFO
例子:
- (void)viewDidLoad { [super viewDidLoad]; // 创建3个 NSInvocationOperation 操作 NSOperationQueue *opQueue = [NSOperationQueue new]; for (NSUInteger i = 0; i < 3; i++) { // 可以传递一个 NSObject 给operation的操作方法 NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Operation_%lu", i] forKey:@"key"]; NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationSelector:) object:dict]; [opQueue addOperation:op]; } } // NSInvocationOperation 操作执行的方法 - (void)operationSelector:(NSDictionary *)dict { // 接收传进来的dict NSLog(@"dictValue = %@", [dict valueForKey:@"key"]); sleep(10); // 加个睡眠模仿耗时操作 NSLog(@"currentThread = %@", [NSThread currentThread]); NSLog(@"mainThread = %@", [NSThread mainThread]); }
2 NSOperationQueue 的其他属性 添加操作有3个方法: // 直接添加一个 NSOperation 操作,并且加入并发队列,只要当前队列允许,就会立刻执行。 - (void)addOperation:(NSOperation *)op; // 添加一组操作,如果 waitUntilFinished 为 NO,则必须在当前队列中的所有操作都执行完了,才会执行这组操作,否则立刻执行。 - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0); // 直接在这里写一个block,block中的操作加入并发队列,并且只要当前队列允许执行,就会立刻执行。 - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0); 接下来看其他的属性 // 返回当前队列中的所有操作NSOperation @property (readonly, copy) NSArray<__kindof NSOperation *> *operations; // 返回当前队列中的操作数量,对应 operations.count @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0); // 可读写的属性,当设备性能不足或根据需求要限制并行的操作数量时,可以设置这个值。 // 设置了这个值之后,队列中并发执行的操作数量不会大于这个值。超出这个值在排队中的操作会处于休眠状态。 // 默认值为 NSOperationQueueDefaultMaxConcurrentOperationCount = -1 @property NSInteger maxConcurrentOperationCount; // 可以给队列指定一个名字用来做标识 @property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0); // 给队列指定一个优先级,默认为 NSQualityOfServiceDefault = -1 @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); // ??? 这个不是太理解 @property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0); // 取消队列中的所有操作。其实就是调用 operations 中每个操作的`cancel`方法才取消操作。 // 但是,在前面的文章中说过,调用`cancel`方法并不会终止操作,而是设置`cancelled`属性为 YES, // 这就需要自己在操作中分节点去判断`cancelled`属性了,在适当的时机结束操作。 - (void)cancelAllOperations; // 调用这个方法时,会判断 NSOperationQueue 中的操作是否全部执行完,如果没有,则调用者所在的线程会在调用处等待。 // 直到 NSOperationQueue 中的所有操作执行完成,当前线程才继续执行。如果 NSOperationQueue 为空,则该方法立刻返回。 - (void)waitUntilAllOperationsAreFinished; // 取得调用者的当前线程中的 NSOperationQueue 操作队列 + (nullable NSOperationQueue *)currentQueue NS_AVAILABLE(10_6, 4_0); // 取得主线程中的 + (NSOperationQueue *)mainQueue NS_AVAILABLE(10_6, 4_0); @property (getter=isSuspended) BOOL suspended;
本次重点为对比handler: 用得到是
// 取得主线程中的
+ (NSOperationQueue *)mainQueue NS_AVAILABLE(10_6, 4_0);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ // UI更新代码 self.alert.text = @"Thanks!"; }];
NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init];
[waitQueue addOperationWithBlock:^{
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
// 同步到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.alert.text = @"Thanks!";
}];
}];
同时提一下还有其它两种UI更新方式
performSelectorOnMainThread
NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init]; [waitQueue addOperationWithBlock:^{ [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]]; // 同步到主线程 [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO]; }]; /** * UI更新函数 */ - (void)updateUI { self.alert.text = @"Thanks!"; }
dispatch_async(dispatch_get_main_queue(), ^{});
NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init]; [waitQueue addOperationWithBlock:^{ [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]]; // 同步到主线程 dispatch_async(dispatch_get_main_queue(), ^{ self.alert.text = @"Thanks!"; }); }];
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)