赞
踩
在 iOS 开发中,进程是一个基本的概念,虽然通常作为开发者,你不需要像在某些其他操作系统那样进行直接的进程管理,因为 iOS 提供了很多高级别的抽象。不过,了解进程的概念对于理解应用程序的运行环境仍然很重要。
进程是一个执行中的程序的实例。它是系统资源(如 CPU 时间、内存空间、文件描述符等)分配的基本单位。每个进程都运行在其自己的隔离空间内,操作系统负责管理进程的生命周期以及它们对系统资源的使用。
出于安全考虑,iOS 上的每个应用程序都运行在一个称为“沙盒”的隔离环境中。这意味着应用程序只能访问分配给自己的文件系统目录,并受限于对设备其他部分的访问。这有助于防止恶意软件破坏系统或窃取数据。
iOS 应用通常作为单个进程运行。尽管应用可以启动多个线程,但它们都是属于同一个进程的。
iOS 操作系统严格管理应用进程的生命周期。应用程序状态(如启动、挂起、恢复、终止)由系统根据资源需求和用户行为管理。
为了保持电池寿命和系统性能,iOS 对后台进程的执行有严格的限制。应用程序通常情况下在退到后台后会被挂起,除非它们声明了后台执行的任务。
iOS 使用引用计数(如 ARC - Automatic Reference Counting)来管理内存。当系统内存不足时,它会自动终止后台进程来释放资源。
iOS 应用程序不能直接调用大多数系统调用,而是通过 iOS SDK 提供的 API 与操作系统交互。这些 API 为进程间通信、资源访问等提供了接口。
在 iOS 中,进程间通信被限制和控制,但仍然提供了几种机制:
在iOS开发中,线程是一个比进程更轻量级的执行单元。一个进程内可以有多个线程,它们共享进程的内存空间和资源,但是每个线程拥有自己的执行序列、栈空间和线程状态。线程可以并行或并发地执行多个任务,从而提高应用程序的效率和响应性。
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
每个线程都有自己的私有栈空间,执行上下文和程序计数器。
线程的创建和上下文切换比进程轻量得多。
同一进程下的线程共享进程的内存和资源。
为了防止数据冲突,通常需要通过锁、信号量等同步机制来控制线程对共享资源的访问。
iOS提供了几种不同的方式来管理和使用线程:
这是一种跨平台的线程API,允许更精细的线程控制。但它不提供自动内存管理,并且使用起来比较复杂。
Swift:
- import Foundation
-
- // 线程执行的函数
- func threadFunction(arg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? {
- print("Thread is now running")
- // 执行一些任务
- print("Thread finishing")
- return nil
- }
-
- // 创建线程
- var thread = pthread_t(bitPattern: 0)
- var attribute = pthread_attr_t()
-
- pthread_attr_init(&attribute)
- pthread_create(&thread, &attribute, { arg in
- return threadFunction(arg: arg)
- }, nil)
- pthread_attr_destroy(&attribute)
-
- // 等待线程结束
- pthread_join(thread!, nil)

OC:
- #import <Foundation/Foundation.h>
- #import <pthread.h>
-
- void *threadFunction(void *arg) {
- NSLog(@"Thread is now running");
- // 执行一些任务
- NSLog(@"Thread finishing");
- return NULL;
- }
-
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- pthread_t thread;
- pthread_attr_t attribute;
-
- pthread_attr_init(&attribute);
- pthread_create(&thread, &attribute, threadFunction, NULL);
- pthread_attr_destroy(&attribute);
-
- // 等待线程结束
- pthread_join(thread, NULL);
- }
- return 0;
- }

NSThread是Objective-C提供的面向对象的线程操作方式。它相对于pthreads简单一些,但仍然需要开发者手动管理线程的生命周期和同步。
Swift:
- import Foundation
-
- // 线程调用的方法
- @objc class ThreadExample: NSObject {
- @objc func threadMethod() {
- print("Thread is now running")
- // 执行一些任务
- print("Thread finishing")
- }
- }
-
- // 创建并启动线程
- let example = ThreadExample()
- let thread = Thread(target: example, selector: #selector(ThreadExample.threadMethod), object: nil)
- thread.start()
-
- // 主线程继续执行其它任务
- print("Main thread is not blocked")

OC:
- #import <Foundation/Foundation.h>
-
- @interface ThreadExample : NSObject
- - (void)threadMethod;
- @end
-
- @implementation ThreadExample
- - (void)threadMethod {
- @autoreleasepool {
- NSLog(@"Thread is now running");
- // 执行一些任务
- NSLog(@"Thread finishing");
- }
- }
- @end
-
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- ThreadExample *example = [[ThreadExample alloc] init];
- NSThread *thread = [[NSThread alloc] initWithTarget:example selector:@selector(threadMethod) object:nil];
- [thread start];
-
- // 主线程继续执行其它任务
- NSLog(@"Main thread is not blocked");
- }
- return 0;
- }

GCD是Apple推荐的多线程解决方案,它使用队列来抽象线程的创建和管理。GCD可以自动管理线程池,优化线程数量,并提供了简单的API来执行异步任务。
Swift:
- import Foundation
-
- // 创建串行队列
- let serialQueue = DispatchQueue(label: "com.example.serialQueue")
-
- // 创建并发队列
- let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
-
- // 在串行队列上异步执行任务
- serialQueue.async {
- for i in 1...3 {
- print("Serial Queue Async Task \(i)")
- }
- }
-
- // 在并发队列上异步执行任务
- concurrentQueue.async {
- for i in 1...3 {
- print("Concurrent Queue Async Task \(i)")
- }
- }
-
- // 在主队列上延迟执行任务
- DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
- print("This task is run on the main queue after 2 seconds")
- }
-
- // 使用全局并发队列
- DispatchQueue.global().async {
- print("Global queue async task")
- }
-
- // 主线程继续执行其他任务
- print("Main thread is not blocked")

下面示例代码的打印顺序?
- override func viewDidLoad() {
- super.viewDidLoad()
-
- DispatchQueue.main.async {
- print("1")
- }
- print("2")
-
- // 创建串行队列
- let serialQueue = DispatchQueue(label: "com.example.serialQueue")
- // 在串行队列上异步执行任务
- serialQueue.async {
- print("3")
- }
- print("4")
-
- // 创建并发队列
- let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
- // 在并发队列上异步执行任务
- concurrentQueue.async {
- print("5")
- }
- print("6")
-
- DispatchQueue.global().sync {
- print("7")
- }
- print("8")
-
- // 获取一个后台队列(优先级为默认)
- let backgroundQueue = DispatchQueue.global(qos: .background)
- // 在后台队列上异步执行任务
- backgroundQueue.async {
- // 放置后台线程需要执行的任务
- print("9")
- }
- print("10")
-
- DispatchQueue.global().async {
- print("11")
- }
- print("12")
- }

DispatchQueue.main.async { print("1") }
这个异步调用将任务排队到主队列,但是它不会立即执行。由于当前代码块已经在主线程上执行(viewDidLoad
),所以这个异步任务将会在当前代码块完成后的某个时间点执行。serialQueue.async { print("3") }
在一个自定义的串行队列上异步执行。它将会在某个不确定的时间点执行,因为它不会阻塞当前线程。但由于它是串行队列,它会保证按照被添加到队列中的顺序执行。concurrentQueue.async { print("5") }
在一个自定义并发队列上异步执行。它可能几乎立即开始执行,但实际的执行时间取决于系统的调度。DispatchQueue.global().sync { print("7") }
在全局并发队列上同步执行,这将会阻塞主线程,直到这个同步任务完成,所以 print("7")
会在 print("6")
之后,而且在 print("8")
之前执行。backgroundQueue.async { print("9") }
在一个全局队列上异步执行,这个队列的优先级是后台。它将在未来某个不确定的时间点执行,不会阻塞主线程。但由于QoS 级别是一个提示给系统的优先级标识,用于决定哪些任务应该先执行。.background
QoS 是最低的优先级,所以执行顺序会靠后。DispatchQueue.global().async { print("11") }
在全局并发队列上异步执行,它会在未来某个不确定的时点执行。综上所述,同步执行的 print
调用将按顺序立即打印,按照 2, 4, 6, 7, 8, 10, 12 的顺序。异步派发的任务,print("1")确定会在最后打印. 其它
的print("3")
, print("5")
, print("9")
, 和 print("11")
将在未来某个时点执行,它们的执行顺序取决于系统对任务的调度和队列的类型(串行或并发), 但print("9")级别最低会在最后执行
。因此,其他异步任务的执行顺序是不确定的。
实际打印顺序为:
2/4/3/6/5/7/8/10/12/11/9/1
也打印成这种:
2/4/6/7/8/3/5/10/12/11/9/1
也会打印成这种 :
2/4/6/3/5/7/8/10/12/11/9/1
OC:
- #import <Foundation/Foundation.h>
-
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- // 创建串行队列
- dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serialQueue", DISPATCH_QUEUE_SERIAL);
-
- // 创建并发队列
- dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
-
- // 在串行队列上异步执行任务
- dispatch_async(serialQueue, ^{
- for (int i = 1; i <= 3; i++) {
- NSLog(@"Serial Queue Async Task %d", i);
- }
- });
-
- // 在并发队列上异步执行任务
- dispatch_async(concurrentQueue, ^{
- for (int i = 1; i <= 3; i++) {
- NSLog(@"Concurrent Queue Async Task %d", i);
- }
- });
-
- // 在主队列上延迟执行任务
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- NSLog(@"This task is run on the main queue after 2 seconds");
- });
-
- // 使用全局并发队列
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSLog(@"Global queue async task");
- });
-
- // 主线程继续执行其他任务
- NSLog(@"Main thread is not blocked");
- }
- return 0;
- }

Operation Queues是基于GCD但更高层次的抽象。它使用NSOperation对象来表示单个任务,可以设置任务的依赖关系,并通过NSOperationQueue来管理任务的执行。
Swift:
- import Foundation
-
- // 创建一个操作队列
- let operationQueue = OperationQueue()
-
- // 创建一个NSBlockOperation来执行任务
- let operation1 = BlockOperation {
- print("Operation 1 is being executed")
- // 模拟一些工作
- Thread.sleep(forTimeInterval: 2)
- print("Operation 1 has finished executing")
- }
-
- // 创建另一个操作
- let operation2 = BlockOperation {
- print("Operation 2 is being executed")
- // 模拟一些工作
- Thread.sleep(forTimeInterval: 1)
- print("Operation 2 has finished executing")
- }
-
- // 添加操作依赖,operation2将会在operation1完成后才开始执行
- operation2.addDependency(operation1)
-
- // 将操作添加到队列中
- operationQueue.addOperation(operation1)
- operationQueue.addOperation(operation2)
-
- // 添加一个操作到队列中,使用addOperation的闭包形式
- operationQueue.addOperation {
- print("Operation 3 is being executed")
- // 执行一些工作
- print("Operation 3 has finished executing")
- }
-
- // 主线程继续执行其他任务
- print("Main thread is not blocked")

OC:
- #import <Foundation/Foundation.h>
-
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- // 创建操作队列
- NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
-
- // 创建NSBlockOperation来执行任务
- NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
- NSLog(@"Operation 1 is being executed");
- // 模拟一些工作
- [NSThread sleepForTimeInterval:2];
- NSLog(@"Operation 1 has finished executing");
- }];
-
- // 创建另一个操作
- NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
- NSLog(@"Operation 2 is being executed");
- // 模拟一些工作
- [NSThread sleepForTimeInterval:1];
- NSLog(@"Operation 2 has finished executing");
- }];
-
- // 添加操作依赖,operation2将会在operation1完成后才开始执行
- [operation2 addDependency:operation1];
-
- // 将操作添加到队列中
- [operationQueue addOperation:operation1];
- [operationQueue addOperation:operation2];
-
- // 使用addOperationWithBlock添加另一个操作到队列中
- [operationQueue addOperationWithBlock:^{
- NSLog(@"Operation 3 is being executed");
- // 执行一些工作
- NSLog(@"Operation 3 has finished executing");
- }];
-
- // 主线程继续执行其他任务
- NSLog(@"Main thread is not blocked");
- }
- return 0;
- }

由于线程共享内存和资源,同步变得非常重要。
iOS提供了多种同步机制来避免数据竞争和条件竞争:
如NSLock、NSRecursiveLock、NSCondition等,用于控制对共享资源的访问。
Swift:
- import Foundation
-
- var sharedResource = [String]()
-
- let lock = NSLock()
-
- func accessSharedResource() {
- lock.lock()
- // 安全地访问共享资源
- sharedResource.append("Data")
- lock.unlock()
- }
-
- // 在不同的线程中调用accessSharedResource()
- DispatchQueue.global().async {
- accessSharedResource()
- }
-
- DispatchQueue.global().async {
- accessSharedResource()
- }

OC:
- #import <Foundation/Foundation.h>
-
- NSMutableArray *sharedResource = [NSMutableArray array];
-
- NSLock *lock = [[NSLock alloc] init];
-
- void accessSharedResource() {
- [lock lock];
- // 安全地访问共享资源
- [sharedResource addObject:@"Data"];
- [lock unlock];
- }
-
- // 在不同的线程中调用accessSharedResource()
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResource();
- });
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResource();
- });

GCD中的dispatch_semaphore_t
可以用来控制对资源的并发访问。
Swift:
- import Foundation
-
- let semaphore = DispatchSemaphore(value: 1)
-
- func accessSharedResourceWithSemaphore() {
- semaphore.wait() // 等待信号量
- // 安全地访问共享资源
- sharedResource.append("Data")
- semaphore.signal() // 释放信号量
- }
-
- // 在不同的线程中调用accessSharedResourceWithSemaphore()
- DispatchQueue.global().async {
- accessSharedResourceWithSemaphore()
- }
-
- DispatchQueue.global().async {
- accessSharedResourceWithSemaphore()
- }

OC:
- #import <Foundation/Foundation.h>
-
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
-
- void accessSharedResourceWithSemaphore() {
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 等待信号量
- // 安全地访问共享资源
- [sharedResource addObject:@"Data"];
- dispatch_semaphore_signal(semaphore); // 释放信号量
- }
-
- // 在不同的线程中调用accessSharedResourceWithSemaphore()
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResourceWithSemaphore();
- });
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResourceWithSemaphore();
- });

如OSAtomic
系列函数,提供了简单的原子性操作。
- #import <libkern/OSAtomic.h>
-
- __block volatile int32_t counter = 0;
-
- void incrementCounter() {
- OSAtomicIncrement32(&counter);
- }
-
- // 在不同的线程中调用incrementCounter()
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- incrementCounter();
- });
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- incrementCounter();
- });

Objective-C中的关键字,可以简化锁的使用。
- #import <Foundation/Foundation.h>
-
- void accessSharedResourceWithSynchronized() {
- @synchronized(sharedResource) {
- // 安全地访问共享资源
- [sharedResource addObject:@"Data"];
- }
- }
-
- // 在不同的线程中调用accessSharedResourceWithSynchronized()
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResourceWithSynchronized();
- });
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- accessSharedResourceWithSynchronized();
- });

iOS中有一个特别重要的线程概念是主线程(Main Thread):
用于更新UI和处理UI事件,以保证用户界面的流畅性。
Swift:
- DispatchQueue.main.async {
- // 更新UI
- // 例如,更新一个标签的文本:
- // self.label.text = "Updated Text"
- }
OC:
- dispatch_async(dispatch_get_main_queue(), ^{
- // 更新UI
- // 例如,更新一个标签的文本:
- // self.label.text = @"Updated Text";
- });
用于执行耗时的任务,如网络请求或大量数据处理,避免阻塞主线程。
Swift:
- DispatchQueue.global(qos: .background).async {
- // 在这里执行耗时的任务
- // 例如,进行一个网络请求或大量数据处理
- let result = "Some Result"
-
- // 当需要更新UI时,回到主线程
- DispatchQueue.main.async {
- // 更新UI
- // self.label.text = result
- }
- }
OC:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
- // 在这里执行耗时的任务
- // 例如,进行一个网络请求或大量数据处理
- NSString *result = @"Some Result";
-
- // 当需要更新UI时,回到主线程
- dispatch_async(dispatch_get_main_queue(), ^{
- // 更新UI
- // self.label.text = result;
- });
- });
开发者应该始终记住在主线程上更新UI,并将耗时的工作放在后台线程上执行。例如,使用GCD可以很容易地在后台执行任务:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // 在后台线程上执行耗时任务
- // ...
-
- dispatch_async(dispatch_get_main_queue(), ^{
- // 回到主线程更新UI
- // ...
- });
- });
在iOS开发中,合理使用线程对于创建流畅、响应式的应用至关重要。避免在主线程上执行耗时操作,以及处理好线程间的同步和通信,是高效iOS应用程序的标志。
在 Swift 和 Objective-C 这两种 iOS 主要的编程语言中,线程使用的概念和操作都是相似的。
队列可以被视为对线程行为的一层抽象,但它们并不是线程本身。
队列提供了一种机制来组织和调度执行任务的顺序,而不需要开发者直接管理线程的创建、同步和其他复杂的线程生命周期问题。
当你操控队列时,你实际上是在告诉系统如何安排这些任务的执行。在iOS中,这通常是通过使用Grand Central Dispatch (GCD) 来实现的。GCD后台自动管理着一个线程池,并根据系统的负载动态地调整线程的使用。这意味着:
由于队列抽象了线程的管理,所以开发者不需要(也不应该)去假设某个任务会在特定的线程上执行。相反,应该关注的是任务的组织、同步和他们的执行方式(串行或并发)。
总之,通过操作队列,你间接地管理了线程的行为,但你并没有直接操控线程。队列的抽象让你能够更专注于任务的逻辑本身,而不是底层的线程管理。这极大地简化了并发编程,并提高了代码的安全性和可维护性。
主队列是一个特殊的串行队列,它用于在主线程上执行任务。由于它在主线程上执行任务,因此它通常用于更新 UI 或处理 UI 事件,以确保用户界面的更新是平滑且同步的。
获取主队列的方式如下:
Swift:
let mainQueue = DispatchQueue.main
使用 DispatchQueue.main
,你可以将任务异步或同步地派发到主线程。通常,你会异步地将任务派发到主线程,以避免阻塞当前线程:
- DispatchQueue.main.async {
- // 更新UI等主线程任务
- }
请注意,尽管你可以同步地派发任务到主队列,但如果你在主线程上这样做,将会导致死锁,因为主线程会等待自己完成任务,这是一个逻辑错误。因此,通常你只会异步地将任务派发到主队列。
OC:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
GCD 提供了几个不同优先级的全局并行队列,这些队列在应用程序是共享的。你可以使用它们来执行并发任务,而不需要自己创建并行队列。全局并行队列有四个优先级:高、默认、低和后台。
获取全局并行队列的方式如下:
Swift:
let globalQueue = DispatchQueue.global(qos: .default)
OC:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
优先级可以是以下之一:
DISPATCH_QUEUE_PRIORITY_HIGH
DISPATCH_QUEUE_PRIORITY_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW
DISPATCH_QUEUE_PRIORITY_BACKGROUND
在iOS开发中,使用Grand Central Dispatch (GCD)可以创建自定义队列(Custom Queues)。自定义队列可以是串行的也可以是并行的,取决于你的需求。以下是创建自定义队列的基本步骤和示例:
串行队列(Serial Queue)保证任务按照添加到队列中的顺序执行,一个接一个地执行。
Swift:
- // 创建自定义串行队列
- let serialQueue = DispatchQueue(label: "com.example.mySerialQueue")
-
- // 异步添加任务到队列
- serialQueue.async {
- // 这里添加需要执行的任务
- print("Task 1 started")
- // 假设这里有一些耗时操作
- print("Task 1 finished")
- }
-
- serialQueue.async {
- // 添加另一个任务
- print("Task 2 started")
- // 同样这里可能有耗时操作
- print("Task 2 finished")
- }
-
- // Task 1 和 Task 2 将按照添加的顺序执行

OC:
- // 创建自定义串行队列
- dispatch_queue_t serialQueue = dispatch_queue_create("com.example.mySerialQueue", DISPATCH_QUEUE_SERIAL);
-
- // 异步添加任务到队列
- dispatch_async(serialQueue, ^{
- NSLog(@"Task 1 started");
- // 假设这里有一些耗时操作
- NSLog(@"Task 1 finished");
- });
-
- dispatch_async(serialQueue, ^{
- NSLog(@"Task 2 started");
- // 同样这里可能有耗时操作
- NSLog(@"Task 2 finished");
- });
-
- // Task 1 和 Task 2 将按照添加的顺序执行

并行队列(Concurrent Queue)允许多个任务并发执行。任务开始的顺序仍然符合其被添加到队列中的顺序,但是它们的执行和结束顺序可能是不一致的,因为任务可以在不同的线程上并发运行。
Swift:
- // 创建自定义并行队列
- let concurrentQueue = DispatchQueue(label: "com.example.myConcurrentQueue", attributes: .concurrent)
-
- // 异步添加任务到队列
- concurrentQueue.async {
- // 添加任务
- print("Task 1 started")
- // 假设耗时操作
- print("Task 1 finished")
- }
-
- concurrentQueue.async {
- // 添加另一个任务
- print("Task 2 started")
- // 假设耗时操作
- print("Task 2 finished")
- }
-
- // Task 1 和 Task 2 可能会同时执行

OC:
- // 创建自定义并行队列
- dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
-
- // 异步添加任务到队列
- dispatch_async(concurrentQueue, ^{
- NSLog(@"Task 1 started");
- // 假设耗时操作
- NSLog(@"Task 1 finished");
- });
-
- dispatch_async(concurrentQueue, ^{
- NSLog(@"Task 2 started");
- // 假设耗时操作
- NSLog(@"Task 2 finished");
- });
-
- // Task 1 和 Task 2 可能会同时执行

自定义队列还可以设置服务质量(Quality of Service,QoS),以指示任务的重要性和执行优先级。
Swift:
- // 创建具有优先级的自定义串行队列
- let highPriorityQueue = DispatchQueue(label: "com.example.myHighPriorityQueue", qos: .userInitiated)
-
- // 用户初始化的任务通常比较紧急,但不会阻塞UI,比如加载操作
- highPriorityQueue.async {
- // 执行高优先级任务
- }
服务质量(QoS)选项包括:
.userInteractive
: 需要立即结果的任务,用于更新UI、处理事件等。.userInitiated
: 用户期望立即得到结果的任务,比如滑动停止后的加载操作。.default
: 默认优先级,如果没有设置QoS,则队列会使用这个。.utility
: 长时间运行的任务,通常带有用户可见的进度指示,如下载文件。.background
: 用户不直接感知的任务,比如数据库维护、数据备份等。.unspecified
: 没有设置QoS。通过设置不同的QoS,系统会为这些任务分配不同的资源,从而影响它们的执行优先级。
OC:
- // 创建具有优先级的自定义串行队列
- dispatch_queue_attr_t qosAttribute = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0);
- dispatch_queue_t highPriorityQueue = dispatch_queue_create("com.example.myHighPriorityQueue", qosAttribute);
-
- // 用户初始化的任务通常比较紧急,但不会阻塞UI,比如加载操作
- dispatch_async(highPriorityQueue, ^{
- // 执行高优先级任务
- NSLog(@"High priority task is being executed.");
- });
在GCD中,你可以选择同步(sync)或异步(async)地将任务添加到队列中:
sync
)在当前线程中执行任务,并阻塞该线程,直到任务完成。
Swift:
- // 获取一个队列(非主队列)
- let queue = DispatchQueue(label: "com.example.queue")
-
- // 同步执行任务
- queue.sync {
- // 这个任务会立即执行,并且调用线程会等待直到任务完成
- }
-
- // 这行代码只有在上面的同步任务完成后才会执行
注意:不要在主队列上同步提交任务,因为这会导致死锁。
OC:
- dispatch_sync(queue, ^{
- // 这个任务会立即执行,并且提交任务的线程会等待直到任务完成
- });
-
- // 这行代码只有在上面的任务完成后才会执行
使用同步执行时要特别注意,如果你在主队列(主线程的串行队列)上同步提交任务,将会导致死锁,因为主队列等待这个同步任务完成,而同步任务又在等待主队列(也就是它自己)空闲,从而形成了相互等待的局面。
async
)允许任务在另一线程中执行,不会阻塞当前线程,调用线程会等待任务完成。
Swift:
- // 获取一个队列
- let queue = DispatchQueue(label: "com.example.queue")
-
- // 异步执行任务
- queue.async {
- // 这个任务会被加入队列中,但不一定会立即执行
- }
-
- // 这行代码会在上面的异步任务提交后立即执行,而不会等待那个任务结束
OC:
- dispatch_async(queue, ^{
- // 这个任务会被加入队列中,但不会立即执行
- });
-
- // 这行代码会在上面的异步任务提交后立即执行,而不会等待那个任务结束
异步执行是并发程序设计中的一项基本技术,允许多个任务并行进行。在 GCD 中,异步提交到串行队列将使任务一个接一个地执行,而异步提交到并发队列则可以让多个任务同时进行。
在iOS开发中,选择合适的队列和执行方式(同步或异步)对于保证应用性能和响应性至关重要。以下是一些基本指南:
在iOS开发中,"任务"一词通常指的是需要完成的工作单元。任务可以是任何事情,从简单的计算到复杂的网络请求。iOS提供了几种不同的方式来处理任务,尤其是在多线程和并发编程方面。
以下是一些iOS开发中任务的基本概念和处理方式。
这些任务需要大量的CPU资源来进行计算。
例子:图像处理,大量数据计算。
这些任务包括文件读写、网络请求等,它们通常等待系统资源的响应。
例子:从硬盘读取文件,从服务器下载数据。
这些任务涉及更新用户界面,必须在主线程上执行。
例子:刷新表视图,更新进度条。
在Grand Central Dispatch (GCD)中,任务通常以两种形式提交给队列:
dispatch_sync
函数用于同步添加任务到指定的队列。dispatch_async
函数用于异步添加任务到指定的队列。- let queue = DispatchQueue(label: "com.example.myQueue", attributes: .concurrent)
-
- queue.async {
- // 执行耗时的任务
- let result = performCalculations()
-
- DispatchQueue.main.async {
- // 在主线程更新UI
- updateUI(with: result)
- }
- }
在GCD中,你不能直接取消已经在执行的任务,但是你可以通过在任务代码中添加取消检查点来协作地取消任务。
- let queue = DispatchQueue(label: "com.example.myQueue")
- var isCancelled = false
-
- queue.async {
- if isCancelled { return }
- // 执行任务
- }
-
- // 取消任务
- isCancelled = true
NSOperation
是另一种用于执行任务的抽象,它比GCD提供更多的控制和灵活性。任务以NSOperation
对象的形式表示,可以添加到NSOperationQueue
中执行。
NSBlockOperation
或自定义子类。NSOperation
对象的执行。- let queue = OperationQueue()
-
- let operation = BlockOperation {
- // 执行耗时的任务
- let result = performCalculations()
-
- OperationQueue.main.addOperation {
- // 在主线程更新UI
- updateUI(with: result)
- }
- }
-
- queue.addOperation(operation)
在NSOperation中,你可以使用cancel
方法来请求取消一个操作,操作对象会检查isCancelled
属性决定是否提前结束任务。
- let operation = BlockOperation {
- // 执行任务
- if operation.isCancelled {
- return
- }
- // 继续执行任务
- }
-
- operationQueue.addOperation(operation)
-
- // 取消操作
- operation.cancel()
在处理任务时,开发者必须注意以下几个挑战:
确保在多线程环境中共享资源的访问是安全的,例如使用锁或串行队列。
合理利用多线程和并发,避免过多地创建线程导致的上下文切换开销。
避免因同步执行或资源竞争造成的死锁情况。
合理分配和回收资源,如内存、文件句柄等。
确保耗时操作不会阻塞主线程,影响UI的流畅度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。