等效于iOS 3.x中的GCD串行调度队列

如何解决等效于iOS 3.x中的GCD串行调度队列

|| Apple的Grand Central Dispatch(GCD)很棒,但仅适用于iOS 4.0或更高版本。 Apple的文档说,“ [[A]序列化操作队列的行为与Grand Central Dispatch中的串行调度队列不完全相同”(因为该队列不是FIFO,但是顺序由依赖项和优先级确定)。 在发布GCD之前支持OS版本的同时,实现与GCD的串行调度队列相同效果的正确方法是什么?或换一种说法,在想要支持低于4.0版本的iOS应用中,推荐的处理简单后台处理(进行Web服务请求等)的方法是什么?     

解决方法

        似乎人们将花很多精力来重写NSRunloop。根据NSRunloop文档:   您的应用程序无法创建   或显式管理NSRunLoop   对象。每个NSThread对象,   包括应用程序的主   线程,具有一个NSRunLoop对象   自动为其创建   需要。 因此,肯定的答案是创建一个可用的队列:
- (void)startRunLoop:(id)someObject
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [[NSRunLoop currentRunLoop] run];

    [pool release];
}

...

NSThread *serialDispatchThread = [[NSThread alloc] 
                   initWithTarget:self 
                   selector:@selector(startRunLoop:) 
                   object:nil];
[serialDispatchThread start];
要将任务添加到队列:
[object
    performSelector:@selector(whatever:) 
    onThread:serialDispatchThread
    withObject:someArgument
    waitUntilDone:NO];
根据“运行循环”中的“线程编程指南”部分:   可可定义了自定义输入源   允许您执行选择器   在任何线程上。 ...执行选择器请求是   在目标线程上序列化,   减轻许多   可能会出现的同步问题   在运行多种方法时发生   在一个线程上。 因此,您已经有了一个明确的串行队列。当然,我的写得不是很出色,因为我已经告诉运行循环永远运行,您可能更喜欢稍后可以终止的运行方式,但这很容易修改。     ,        这个PseudoSerialQueue怎么样?这是一个最小的实现,例如调度串行队列。
#import <Foundation/Foundation.h>

@interface PseudoTask : NSObject
{
    id target_;
    SEL selector_;
    id queue_;
}

@property (nonatomic,readonly) id target;

- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
- (void)exec;
@end

@implementation PseudoTask

@synthesize target=target_;

- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
{
    self = [super init];
    if (self) {
        target_ = [target retain];
        selector_ = selector;
        queue_ = [queue retain];
    }
    return self;
}

- (void)exec
{
    [target_ performSelector:selector_];
}

- (void)dealloc
{
    [target_ release];
    [queue_ release];
}
@end

@interface PseudoSerialQueue : NSObject
{
    NSCondition *condition_;
    NSMutableArray *array_;
    NSThread *thread_;
}
- (void)addTask:(id)target selector:(SEL)selector;
@end

@implementation PseudoSerialQueue
- (id)init
{
    self = [super init];
    if (self) {
        array_ = [[NSMutableArray alloc] init];
        condition_ = [[NSCondition alloc] init];
        thread_ = [[NSThread alloc]
            initWithTarget:self selector:@selector(execQueue) object:nil];
        [thread_ start];
    }
    return self;
}

- (void)addTask:(id)target selector:(SEL)selector
{
    [condition_ lock];
    PseudoTask *task = [[PseudoTask alloc]
        initWithTarget:target selector:selector queue:self];
    [array_ addObject:task];
    [condition_ signal];
    [condition_ unlock];
}

- (void)quit
{
    [self addTask:nil selector:nil];
}

- (void)execQueue
{
    for (;;) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        [condition_ lock];
        while (array_.count == 0)
            [condition_ wait];
        PseudoTask *task = [array_ objectAtIndex:0];
        [array_ removeObjectAtIndex:0];
        [condition_ unlock];

        if (!task.target) {
            [pool drain];
            break;
        }

        [task exec];
        [task release];

        [pool drain];
    }
}

- (void)dealloc
{
    [array_ release];
    [condition_ release];
}
@end
如何使用:
PseudoSerialQueue *q = [[[PseudoSerialQueue alloc] init] autorelease];
[q addTask:self selector:@selector(test0)];
[q addTask:self selector:@selector(test1)];
[q addTask:self selector:@selector(test2)];
[q quit];
    ,        您可以使用
NSOperationQueue
进行模拟,然后将任务计数设置为1。 编辑 -糟糕,应该仔细阅读。 fifo解决方案如下: 我想不出大多数ios开发人员会在您的情况下使用的方式。 我不害怕编写线程程序,因此这里是一种解决方案: 创建一个fifo工作者队列,该队列: 支持锁定 拥有一个NSOperationQueue 拥有一个NSOperation子类,该子类旨在在实施
main
时将其从fifo队列中拉出。一次只能存在一个。 拥有要运行的NSArray的工作程序(定义一个工作程序取决于您-是NSInvocation,类,操作等) NSOperation子类将工作程序从fifo工作程序队列中拉出,直到fifo工作程序队列用尽。 当fifo工作队列中有工作程序且没有活动的子操作时,它将创建一个子操作,并将其添加到其操作队列中。 如果您不习惯编写线程程序,则有一些陷阱-出于这个原因,该解决方案并不适合每个人,但是如果您已经熟悉使用所需的所有技术,则此解决方案的编写时间不会太长。 祝好运     ,        NSOperationQueue文档编写人员忘记了一些事情,实际上使这种实现显得微不足道。 将最大并发操作数设置为1保证仅是串行的 如果NSOperations是从同一线程添加到队列的。 我正在使用另一个选项,因为它可以正常工作。 从不同线程添加NSOperation,但使用NSCondition来管理队列。 可以使用performSelectorOnBackgroundThread调用startOperations(并且应该不要用锁来阻塞主线程)。 startOperations方法表示由一个或多个NSOperations组成的单个作业。
- (void)startOperations
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [[AppDelegate condition] lock];

    while (![[[AppDelegate queue] operations] count] <= 0) 
    {
        [[AppDelegate condition] wait];
    }

    NSOperation *newOperation = [alloc,init]....;
    [[AppDelegate queue] addOperation:newOperation];
    [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don\'t forget this!

    NSOperation *newOperation1 = [alloc,init]....;
    [[AppDelegate queue] addOperation:newOperation1];
    [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don\'t forget this!

    NSOperation *newOperation2 = [alloc,init]....;
    [[AppDelegate queue] addOperation:newOperation2];
    [[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don\'t forget this!

    // Add whatever number operations you need for this single job

    [[AppDelegate queue] signal];
    [[AppDelegate queue] unlock];

    [NotifyDelegate orWhatever]

    [pool drain];
}
而已!     ,        如果处理仍在后台进行,您是否真的需要严格按顺序进行处理?如果这样做,则只需设置依赖项就可以达到相同的效果,因此1依赖于0、2对1、3对2等,然后强制操作队列按顺序处理它们。将最大并发操作数设置为1,并且还保证队列是串行的。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-