并发编程:从操作队列到GCD的优化之旅
立即解锁
发布时间: 2025-08-25 02:23:55 阅读量: 2 订阅数: 8 


Mac上Cocoa编程入门指南
### 并发编程:从操作队列到GCD的优化之旅
在软件开发中,并发编程是提高应用程序性能和响应能力的关键技术。本文将详细介绍如何使用操作队列(Operation Queues)和Grand Central Dispatch(GCD)来优化一个名为SlowWorker的应用程序,使其能够更高效地处理任务。
#### 操作队列优化SlowWorker
首先,我们来看看如何使用操作队列来优化SlowWorker应用程序。在开始之前,我们需要复制整个SlowWorker项目文件夹,因为后续我们将使用原始版本的项目作为另一种并发实现方式的起点。
SlowWorker应用程序的问题在于其单个操作方法按顺序调用多个其他方法,导致应用程序响应迟缓。为了解决这个问题,我们将每个方法封装到一个操作中,并将所有操作放入一个队列中,让队列来管理它们的执行。
以下是具体的操作步骤:
1. **添加`__block`存储限定符**:在`doWork:`方法中,我们为所有本地`NSString`变量添加`__block`存储限定符。这样,每个块都可以读写这些变量,实现数据共享。
2. **创建操作**:使用`NSBlockOperation`为每个工作方法创建操作。例如:
```objc
NSBlockOperation *fetch = [NSBlockOperation blockOperationWithBlock:^{
fetchedData = [self fetchSomethingFromServer];
_resultsTextView.string = [_resultsTextView.string stringByAppendingFormat:
@"Fetched: %@\n", fetchedData];
}];
```
3. **定义依赖关系**:为操作定义依赖关系,确保它们按正确顺序执行。例如,`process`操作依赖于`fetch`操作,`calcFirst`和`calcSecond`操作依赖于`process`操作,`showResults`操作依赖于`calcFirst`和`calcSecond`操作。
```objc
[process addDependency:fetch];
[calcFirst addDependency:process];
[calcSecond addDependency:process];
[showResults addDependency:calcFirst];
[showResults addDependency:calcSecond];
```
4. **创建操作队列**:创建一个新的`NSOperationQueue`,并将所有操作添加到队列中。
```objc
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[fetch, process, calcFirst, calcSecond, showResults]
waitUntilFinished:NO];
```
通过以上步骤,我们可以让操作队列自动管理操作的执行顺序,提高应用程序的响应能力。
#### 确保在主线程访问UI
然而,我们还需要注意AppKit类的线程安全性。由于AppKit类(如窗口和视图类)通常不是线程安全的,所有对它们的访问都应该在主线程上进行。因此,我们需要调整操作,确保对`NSTextView`的访问都在主线程上进行。
以下是修改后的`doWork:`方法:
```objc
- (IBAction)doWork:(id)sender {
NSDate *startTime = [NSDate date];
__block NSString *fetchedData;
__block NSString *processed;
__block NSString *firstResult;
__block NSString *secondResult;
self.isWorking = YES;
NSBlockOperation *fetch = [NSBlockOperation blockOperationWithBlock:^{
fetchedData = [self fetchSomethingFromServer];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_resultsTextView.string = [_resultsTextView.string stringByAppendingFormat:
@"Fetched: %@\n", fetchedData];
}];
}];
NSBlockOperation *process = [NSBlockOperation blockOperationWithBlock:^{
processed = [self processData:fetchedData];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_resultsTextView.string = [_resultsTextView.string stringByAppendingFormat:
@"Processed: %@\n", processed];
}];
}];
NSBlockOperation *calcFirst = [NSBlockOperation blockOperationWithBlock:^{
firstResult = [self calculateFirstResult:processed];
}];
NSBlockOperation *calcSecond = [NSBlockOperation blockOperationWithBlock:^{
secondResult = [self calculateSecondResult:processed];
}];
NSBlockOperation *showResults = [NSBlockOperation blockOperationWithBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_resultsTextView.string = [_resultsTextView.string stringByAppendingFormat:
@"First Result: [%@]\nSecond Result: [%@]\n\n",
firstResult, secondResult];
NSDate *endTime = [NSDate date];
NSLog(@"Completed in %f seconds",
[endTime timeIntervalSinceDate:startTime]);
self.isWorking = NO;
}];
}];
[process addDependency:fetch];
[calcFirst addDependency:process];
[calcSecond addDependency:process];
[showResults addDependency:calcFirst];
[showResults addDependency:calcSecond];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[fetch, process, calcFirst, calcSecond, showResults]
waitUntilFinished:NO];
}
```
通过以上修改,我们确保了对`NSTextView`的访问都在主线程上进行,避免了线程安全问题。
#### 增强用户界面体验
为了进一步提高用户体验,我们可以使用Cocoa Bindings和`isWorking`属性来添加进度指示器。具体操作如下:
1. **添加圆形进度指示器**:打开`MainMenu.xib`文件,使用对象库找到圆形进度指示器,并将其添加到窗口中。
2. **配置圆形进度指示器**:选择进度指示器,使用属性检查器关闭“Display When Stopped”复选框。然后,使用绑定检查器将其“Animate”参数绑定到应用程序委托的`isWorking`属性。
3. **配置开始按钮**:选择开始按钮,将其“Enabled”属性绑定到应用程序委托的`isWorking`属性,并添加`NSNegateBoolean`作为值转换器。
通过以上配置,当用户点击开始按钮时,按钮将变为禁用状态,圆形进度指示器将出现并开始旋转。当工作完成后,进度指示器将消失,按钮将恢复正常。
#### 添加水平进度指示器
除了圆形进度指示器,我们还可以添加水平进度指示器来显示工作进度。具体操作如下:
1. **添加`completed`属性**:在`SWAppDelegate.h`文件中添加一个名为`completed`的新属性。
```objc
// SWAppDelegate.h
```
0
0
复制全文
相关推荐









