Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 使用NSRecursive锁等待操作完成_Iphone_Objective C_Multithreading - Fatal编程技术网

Iphone 使用NSRecursive锁等待操作完成

Iphone 使用NSRecursive锁等待操作完成,iphone,objective-c,multithreading,Iphone,Objective C,Multithreading,使用NSRecursiveLock故意在后台线程上等待操作完成是否可以保存?以下是一个例子: 我有一个类,我想有一个loadParts函数,可以是异步的,也可以是同步的。异步函数可能会提前调用,以便在实际需要数据之前加载部件。同步进程应检查数据是否已加载或当前正在加载。如果已加载,则只需返回数据;如果当前已加载,则应等待加载,然后返回;如果它甚至没有被加载,那么它应该同步加载它。这是我尝试使用的代码: // Private function to be run either on main th

使用NSRecursiveLock故意在后台线程上等待操作完成是否可以保存?以下是一个例子:

我有一个类,我想有一个loadParts函数,可以是异步的,也可以是同步的。异步函数可能会提前调用,以便在实际需要数据之前加载部件。同步进程应检查数据是否已加载或当前正在加载。如果已加载,则只需返回数据;如果当前已加载,则应等待加载,然后返回;如果它甚至没有被加载,那么它应该同步加载它。这是我尝试使用的代码:

// Private function to be run either on main thread or
// background thread
-(void)_loadParts
{
    [_loadingPartsLock lock];
    _loadingParts = YES;

    // Do long loading operation

    _loadingParts = NO;
    _partsLoaded = YES;
    [_loadingPartsLock unlock];
}

// Asynchronous loading of parts
-(void)preloadParts
{
    if( _loadingParts || _partsLoaded )
        return;

    [self performSelectorInBackground:@selector(_loadParts) withObject:nil];
}

// Synchronous loading of parts
-(void)loadParts
{
    if( _loadingParts )
    {
        [_loadingPartsLock lock];
        [_loadingPartsLock unlock];
    }

    if( !_partsLoaded )
    {
         [self _loadParts];
    }
}
这样做安全/有效吗?我已经看到了一些可能的问题。在没有锁的情况下设置和测试BOOL的值是线程安全的吗?如果在后台线程仍在加载的情况下调用同步函数,我还会在同步函数中锁定两次

是否有更常见和更好的方法来实现此功能


谢谢

远、远、更好的解决方案是使用
dispatch_队列
NSOperationQueue
(配置为串行操作)

将加载操作排队,然后将完成时应该发生的任何事情排队。如果“done”操作是“tell the main thread to update”,则可以在主线程上执行一个方法,该方法实际上是一个触发更新以响应现在加载的数据的事件


这避免了与完全锁定相关的问题和开销,同时也解决了“已完成”通知问题,而不需要某种轮询机制。

一个更好的解决方案是使用
调度队列
NSOperationQueue
(为串行操作配置)

将加载操作排队,然后将完成时应该发生的任何事情排队。如果“done”操作是“tell the main thread to update”,则可以在主线程上执行一个方法,该方法实际上是一个触发更新以响应现在加载的数据的事件


这避免了与完全锁定相关的问题和开销,同时也解决了“完成”通知问题,而不需要某种轮询机制。

受bbum答案的启发,我找到了一种使用NSOperationQueue的解决方案,但与他描述的方式不同。在preloadParts函数中,我创建并存储一个加载操作,该操作是运行后台线程函数的NSInvocationOperation的实例。然后将其添加到NSOperationQueue

如果在任何时候,数据是由另一个类请求的。我首先检查数据是否已加载(变量已设置)。如果没有,我检查操作是否在队列中。如果是,那么我调用[\u loadOperation waituntillfinished]。否则,我将其添加到操作队列中,参数为waitUntilFinished。下面是我想出的代码:

-(void)preloadCategories
{
    if( [[_operationQueue operations] containsObject:_loadOperation] )
        return;

    [_operationQueue addOperation:_loadOperation];
}

-(CCPart*)getCategoryForName:(NSString*)name
{
    if( nil == _parts )
    {
        [self loadCategories];
    }
    return [_parts objectForKey:name];
}

-(void)loadCategories
{
    if( nil != _parts )
        return;

    if( [[_operationQueue operations] containsObject:_loadOperation] )
    {
        [_loadOperation waitUntilFinished];
    }
    else
    {
        [_operationQueue addOperations:[NSArray arrayWithObject:_loadOperation]
                     waitUntilFinished:YES];
    }
}

-(void)_loadCategories
{
    // Function that actually does the loading and sets _parts to be an array of the data
    _parts = [NSArray array];
}
在初始化函数中,我将_operationQueue和_loadOperation设置如下:

_operationQueue = [[NSOperationQueue alloc] init];
            _loadOperation = [[NSInvocationOperation alloc] initWithTarget:self 
                                                                  selector:@selector(_loadCategories) 
                                                                    object:nil];

受bbum答案的启发,我找到了一个使用NSOperationQueue的解决方案,但与他描述的方式不同。在preloadParts函数中,我创建并存储一个加载操作,该操作是运行后台线程函数的NSInvocationOperation的实例。然后将其添加到NSOperationQueue

如果在任何时候,数据是由另一个类请求的。我首先检查数据是否已加载(变量已设置)。如果没有,我检查操作是否在队列中。如果是,那么我调用[\u loadOperation waituntillfinished]。否则,我将其添加到操作队列中,参数为waitUntilFinished。下面是我想出的代码:

-(void)preloadCategories
{
    if( [[_operationQueue operations] containsObject:_loadOperation] )
        return;

    [_operationQueue addOperation:_loadOperation];
}

-(CCPart*)getCategoryForName:(NSString*)name
{
    if( nil == _parts )
    {
        [self loadCategories];
    }
    return [_parts objectForKey:name];
}

-(void)loadCategories
{
    if( nil != _parts )
        return;

    if( [[_operationQueue operations] containsObject:_loadOperation] )
    {
        [_loadOperation waitUntilFinished];
    }
    else
    {
        [_operationQueue addOperations:[NSArray arrayWithObject:_loadOperation]
                     waitUntilFinished:YES];
    }
}

-(void)_loadCategories
{
    // Function that actually does the loading and sets _parts to be an array of the data
    _parts = [NSArray array];
}
在初始化函数中,我将_operationQueue和_loadOperation设置如下:

_operationQueue = [[NSOperationQueue alloc] init];
            _loadOperation = [[NSInvocationOperation alloc] initWithTarget:self 
                                                                  selector:@selector(_loadCategories) 
                                                                    object:nil];

我想这就是为什么我们有条件。我想这就是为什么我们有条件。谢谢你的回答。我不希望在数据加载完成后立即执行操作。大多数情况下,此操作将提前调用,不会出现问题(数据将有足够的时间加载)。我只是想要一个额外的预防措施,如果数据还没有完成加载,它将(最坏的情况)阻塞线程,直到它完成。这是我正在制作的框架的一个公共类,所以我不希望用户担心注册回调或类似的事情。谢谢你的回答。我不希望在数据加载完成后立即执行操作。大多数情况下,此操作将提前调用,不会出现问题(数据将有足够的时间加载)。我只是想要一个额外的预防措施,如果数据还没有完成加载,它将(最坏的情况)阻塞线程,直到它完成。这是我正在制作的框架的一个公共类,所以我不想让用户担心注册回调之类的事情。