Objective-C编程中的多线程与文件系统操作
立即解锁
发布时间: 2025-08-24 01:09:17 阅读量: 1 订阅数: 6 


Objective-C编程入门与实践
### Objective-C 编程中的多线程与文件系统操作
#### 1. Grand Central Dispatch 概述
Grand Central Dispatch(GCD)由苹果公司推出,它与块(blocks)一同为开发者提供了在应用程序中轻松使用多线程的方式。传统的多线程编程着眼于执行线程(逐行代码),而 GCD 则从队列的角度看待线程。工作被分派到队列中,然后出队执行。
GCD 的调度队列实际上封装了 POSIX 线程工作队列(一种线程池形式),并且在使用这些队列方面非常高效。创建和使用调度队列的成本很低。下面我们先关注如何使用内置队列,之后再探讨创建自定义调度队列等更高级的技术。
#### 2. 内置队列的使用
调度队列由 `dispatch_queue_t` 数据类型表示,这是一种不透明的数据结构,我们不应直接访问其内部状态。主队列代表主线程,可以通过 `dispatch_get_main_queue()` 访问。系统中还有其他全局队列,可以通过 `dispatch_get_global_queue` 方法访问。
以下是使用 `dispatch_async` 进行异步调度的示例代码:
```objc
dispatch_queue_t targeQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(targetQueue, ^{
//perform some high-priority task in the background
dispatch_async(dispatch_get_main_queue(), ^{
//update the UI from the main queue
});
});
```
使用 `dispatch_async` 时,方法调用会立即返回,块会在目标队列上最终执行。而 `dispatch_sync` 会使调用它的线程阻塞,直到块从目标队列中出队并执行完毕。需要注意的是,如果在调用 `dispatch_sync()` 时使用与调用它相同的目标队列,会导致应用程序无限挂起。
除了同步和异步调度,还可以在一定时间间隔后触发块的出队。示例代码如下:
```objc
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"Executed after 2 seconds");
});
```
#### 3. 创建自定义调度队列
可以使用 `dispatch_queue_create` 方法创建自定义调度队列,该方法需要一个 C 字符串作为队列名称(通常与包标识符相关联)和一个属性。目前可用的属性有 `DISPATCH_QUEUE_SERIAL`(定义为 `NULL`,用于普通的先进先出排队行为)和 `DISPATCH_QUEUE_CONCURRENT`(允许块与同一队列上的其他块并发地出队和执行)。
以下是创建自定义调度队列的示例代码:
```objc
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.myApp.backgroundQueue", NULL);
dispatch_async(backgroundQueue, ^{
NSLog(@"Some code to execute in the background");
});
dispatch_release(backgroundQueue);
```
每次调用 `dispatch_queue_create` 或 `dispatch_retain` 时,都必须使用创建的队列调用 `dispatch_release` 进行匹配。队列有一个引用计数,创建时设置为 1,当引用计数达到 0 时,队列会被系统重用。在 OS X 10.8 和 iOS 6 及更高版本中,调度队列在 Objective-C 程序中是 Objective-C 对象,这意味着如果目标操作系统是这些版本或更高版本,ARC 会自动管理调度对象的引用和释放。
#### 4. 调度队列的暂停和恢复
可以使用 `dispatch_suspend` 和 `dispatch_resume` 函数分别暂停和恢复调度对象(如队列)。这些暂停操作可以嵌套,每个队列会记录暂停的次数,每次暂停时计数器加 1,每次恢复时计数器减 1。调用这些方法时必须保持平衡,并且不要尝试暂停主队列或全局队列,因为这些队列不能被暂停。
以下是暂停和恢复队列的示例代码:
```objc
dispatch_queue_t backgroundQueue;
// ...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
dispatch_suspend(backgroundQueue);
//perform some action here, possibly even enqueue more blocks onto backgroundQueue
dispatch_resume(backgroundQueue);
});
```
#### 5. 使用 GCD 进行线程同步
由于队列是先进先出的,并且不允许块并行执行,因此可以在不使用昂贵锁的情况下实现线程同步。通过仅在特殊队列中访问共享数据结构,可以实现对其的同步访问。
以下是使用 GCD 进行线程同步的示例代码:
```objc
@implementation MyThreadSafeObject
{
dispatch_queue_t lockQueue;
id obj;
}
-(id)init
{
if (!(self = [super init]))
return nil;
lockQueue = dispatch_queue_create("com.myApp.lockQueue", NULL);
return self;
}
-(void)dealloc
{
dispatch_release(lockQueue);
}
-(void)setObject:(id)theObj
{
dispatch_sync(lockQueue, ^{
obj = theObj;
});
}
-(id)obj
{
__block result;
dispatch_sync(lockQueue, ^{
result = obj;
});
return result;
}
@end
```
#### 6. 并发队列的特殊操作
在使用并发后台队列时,有时需要提交一个不能并发执行的块。可以使用 `dispatch_barrier_sync` 和 `dispatch_barrier_async` 等待已入队的块执行完毕,然后再单独执行新入队的块,之后才会执行后续入队的块。需要注意的是,在非并发调度队列上调用这些屏障方法没有效果,在串行队列上入队块的所有调用类似于在并发队列上的屏障调用。
以下是使用 `dispatch_barrier_async` 的示例代码:
```objc
dispatch_queue_t backgroundQueue = dispatch
```
0
0
复制全文
相关推荐










