block
的内部实现,结构体是什么样的
在Objective-C中,block是一种闭包,它可以封装一段代码以及其执行环境。当我们定义一个block时,它在编译后的底层存储结构是一个结构体。
下面是block的底层结构体示例:
objective-c
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
};
__block_impl
结构体是所有block结构体的基础,它包含了一些通用的字段,如isa
指针、标志位和保留字段。__main_block_impl_0
结构体是具体的block结构体,它继承自__block_impl
结构体,并包含了block的描述信息和捕获的外部变量。
在上面的示例中,__main_block_impl_0
结构体中有一个age
字段,表示捕获的外部变量。当我们调用block时,实际上是通过FuncPtr
函数指针找到封装的函数并将block的地址作为参数传给这个函数进行执行。在函数执行过程中,可以通过结构体中的字段访问捕获的外部变量。
需要注意的是,block的底层结构体可能会根据具体的情况而有所不同,上述示例只是一个简单的示意。具体的结构体定义可能会根据编译器和代码的不同而有所变化。
Learn more:
iOS开发中有多少类型的线程?分别对比
在iOS开发中,常见的线程类型有以下几种:
-
主线程(Main Thread):也称为UI线程,用于处理用户界面的更新和事件响应。所有UI相关的操作都必须在主线程上执行,否则会导致界面卡顿或崩溃。
-
后台线程(Background Thread):用于执行耗时的任务,不会阻塞主线程。可以使用GCD(Grand Central Dispatch)或NSOperationQueue来创建和管理后台线程。
-
全局并发队列(Global Concurrent Queue):是GCD提供的一种并发队列,可以同时执行多个任务。全局并发队列是系统提供的,不需要手动创建,可以通过
dispatch_get_global_queue
函数获取。 -
自定义并发队列(Custom Concurrent Queue):可以使用GCD创建自定义的并发队列,用于执行多个任务。自定义并发队列可以通过
dispatch_queue_create
函数创建。 -
串行队列(Serial Queue):是一种特殊的自定义队列,用于按顺序执行任务,每次只能执行一个任务。串行队列可以通过
dispatch_queue_create
函数创建。 -
主队列(Main Queue):是一种特殊的串行队列,用于在主线程上执行任务。主队列是系统提供的,不需要手动创建,可以通过
dispatch_get_main_queue
函数获取。 -
主队列和全局并发队列的比较:
- 主队列只在主线程上执行任务,适用于更新UI和处理用户事件等操作。
- 全局并发队列可以在后台线程上执行任务,适用于执行耗时操作和并发执行多个任务。
-
线程安全性:
- 主队列和主线程是线程安全的,可以直接在主队列或主线程上执行任务。
- 全局并发队列和后台线程是非线程安全的,需要使用锁或其他同步机制来保证数据的安全访问。
综上所述,iOS开发中常见的线程类型包括主线程、后台线程、全局并发队列、自定义并发队列、串行队列和主队列。不同的线程类型适用于不同的场景,需要根据具体需求选择合适的线程类型来执行任务。
-
NSThread,每个 NSThread对象对应一个线程,量级较轻,通常我们会起一个 runloop 保活,然后通过添加自定义source0源或者 perform onThread 来进行调用,优点轻量级,使用简单,缺点:需要自己管理线程的生命周期,保活,另外还会线程同步,加锁、睡眠和唤醒。
-
GCD:Grand Central Dispatch(派发) 是基于C语言的框架,可以充分利用多核,是苹果推荐使用的多线程技术
- 优点:GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的,有待确认
- 缺点:操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现
-
NSOperation
-
优点: 使用者的关注点都放在了 operation 上,而不需要线程管理。
- 支持在操作对象之间依赖关系,方便控制执行顺序。
- 支持可选的完成块,它在操作的主要任务完成后执行。
- 支持使用KVO通知监视操作执行状态的变化。
- 支持设定操作的优先级,从而影响它们的相对执行顺序。
- 支持取消操作,允许您在操作执行时暂停操作。
-
缺点:高级抽象,性能方面相较 GCD 来说不足一些;
-
Learn more:
GCD有哪些队列,默认提供哪些队列
GCD(Grand Central Dispatch)是一套用于多线程编程的低层API,它提供了一种方便的方式来管理并发任务。在GCD中,有多种类型的队列可供使用,包括默认提供的队列。
以下是GCD中常用的队列类型和默认提供的队列:
-
主队列(Main Queue):主队列是一个串行队列,用于在主线程上执行任务。它是由系统自动创建的,可以通过调用
dispatch_get_main_queue()
来获取主队列的引用。 -
全局并发队列(Global Concurrent Queue):全局并发队列是一个并行队列,用于在后台线程上执行任务。它提供了多个优先级,可以根据任务的重要性选择不同的优先级。可以通过调用
dispatch_get_global_queue()
来获取全局并发队列的引用。 -
自定义队列(Custom Queue):除了主队列和全局并发队列,还可以创建自定义队列。自定义队列可以是串行队列(Serial Queue)或并行队列(Concurrent Queue)。串行队列按照任务的提交顺序依次执行,而并行队列可以同时执行多个任务。可以通过调用
dispatch_queue_create()
来创建自定义队列。
总结起来,GCD提供了三种常用的队列类型:主队列、全局并发队列和自定义队列。主队列用于在主线程上执行任务,全局并发队列用于在后台线程上执行任务,而自定义队列可以根据需要选择串行或并行执行任务。
Learn more:
GCD有哪些方法api
GCD(Grand Central Dispatch)是iOS开发中常用的多线程编程技术之一,它提供了一系列的API来管理和调度任务的执行。下面是一些常用的GCD方法API:
-
创建Dispatch Queue:
dispatch_queue_create
:创建一个自定义的Dispatch Queue [2].
-
获取系统提供的Dispatch Queue:
-
向Dispatch Queue中追加任务:
-
延迟执行任务:
dispatch_after
:在指定的时间后执行任务 [2].
-
Dispatch Group:
-
Dispatch Barrier:
dispatch_barrier_async
:将指定的任务追加到Concurrent Dispatch Queue中,并在该任务执行完毕后再继续执行其他任务 [3].
这些是GCD中常用的方法API,通过它们可以实现多线程编程和任务调度。更多关于GCD的详细使用方法和说明,可以参考相关的文档和教程。
Learn more:
如何实现同步,有多少方式就说多少
在iOS中,实现同步的方式有多种。下面是一些常用的同步方式:
-
使用GCD(Grand Central Dispatch):
- 使用
dispatch_sync
函数将任务同步提交到指定的队列中,等待任务执行完成后再继续执行后续代码。 - 使用
dispatch_barrier_sync
函数将任务同步提交到自定义的并行队列中,等待任务执行完成后再继续执行后续代码。 - 使用
dispatch_group_wait
函数等待指定的任务组中的任务执行完成后再继续执行后续代码。
- 使用
-
使用NSOperation和NSOperationQueue:
- 将任务封装成NSOperation对象,然后将NSOperation对象添加到NSOperationQueue中。
- 设置NSOperationQueue的
maxConcurrentOperationCount
属性为1,使任务串行执行。
-
使用锁:
- 使用OSSpinLock、os_unfair_lock、pthread_mutex等互斥锁来保证多线程访问共享资源的同步性。
- 使用NSLock、NSRecursiveLock、NSCondition等对象来实现线程同步。
-
使用信号量:
- 使用dispatch_semaphore_create函数创建一个信号量,使用dispatch_semaphore_wait函数等待信号量,使用dispatch_semaphore_signal函数发送信号量。
-
使用dispatch_once函数:
- 使用dispatch_once函数可以保证某个代码块只会被执行一次,常用于单例模式的实现。
这些是iOS中常用的同步方式,根据具体的需求和场景选择合适的方式来实现同步操作。
Learn more:
有哪些类型的线程锁,分别介绍下作用和使用场景
iOS中常用的线程锁类型包括:
-
OSSpinLock(自旋锁)
- 作用:用于保护临界区,确保只有一个线程可以访问共享资源。
- 使用场景:适用于临界区执行时间短且线程竞争不激烈的情况。注意,OSSpinLock在iOS10之后已经不再线程安全[1]。
-
os_unfair_lock(互斥锁)
- 作用:用于保护临界区,确保只有一个线程可以访问共享资源。
- 使用场景:适用于临界区执行时间长或线程竞争激烈的情况。os_unfair_lock是一种高性能的互斥锁,取代了OSSpinLock[1]。
-
dispatch_semaphore(信号量)
- 作用:用于控制同时访问共享资源的线程数量。
- 使用场景:适用于需要限制并发线程数量的情况,比如控制并发网络请求的数量[1]。
-
pthread_mutex(互斥锁)
- 作用:用于保护临界区,确保只有一个线程可以访问共享资源。
- 使用场景:适用于临界区执行时间长或线程竞争激烈的情况。pthread_mutex是一种标准的互斥锁,可以通过不同的属性设置来满足不同的需求[1]。
-
NSLock(互斥锁)
- 作用:用于保护临界区,确保只有一个线程可以访问共享资源。
- 使用场景:适用于临界区执行时间长或线程竞争激烈的情况。NSLock是Foundation框架提供的一种简单的互斥锁[1]。
-
NSCondition(条件锁)
- 作用:用于线程之间的等待和唤醒。
- 使用场景:适用于需要线程间通信的情况,可以通过条件变量来实现线程的等待和唤醒操作[1]。
-
NSRecursiveLock(递归锁)
- 作用:允许同一线程多次加锁,避免死锁。
- 使用场景:适用于同一线程需要多次加锁的情况,比如递归操作或循环中的加锁操作[1]。
-
@synchronized(递归锁)
- 作用:允许同一线程多次加锁,避免死锁。
- 使用场景:适用于同一线程需要多次加锁的情况,比如递归操作或循环中的加锁操作。@synchronized是Objective-C语言提供的一种简单的递归锁机制[1]。
-
pthread_mutex(recursive)(递归锁)
- 作用:允许同一线程多次加锁,避免死锁。
- 使用场景:适用于同一线程需要多次加锁的情况,比如递归操作或循环中的加锁操作。pthread_mutex(recursive)是pthread库提供的一种递归锁机制[1]。
Learn more:
NSTimer、CADisplayLink、dispatch_source_t 的优劣
NSTimer, CADisplayLink, and dispatch_source_t are three different timers available in iOS, each with its own advantages and disadvantages. Let's compare them:
NSTimer:
- Advantages:
- Easy to use and widely used in iOS development.
- Can be scheduled on the main run loop with a specified time interval.
- Disadvantages:
- Limited precision, as it relies on the run loop and may be affected by other activities on the main thread [1].
- May not be suitable for real-time or high-precision timing requirements.
CADisplayLink:
- Advantages:
- Synchronized with the display refresh rate, typically 60 frames per second.
- Provides smooth animations and updates.
- Disadvantages:
- Limited to the refresh rate of the display, which may not be suitable for all timing requirements.
- Can only be used for UI-related tasks and not for general-purpose timing.
dispatch_source_t:
- Advantages:
- Provides high-precision timing and is suitable for real-time tasks.
- Can be used for both UI and non-UI related tasks.
- Offers various dispatch sources, including timers, signals, file descriptors, and more.
- Disadvantages:
- Requires a good understanding of Grand Central Dispatch (GCD) and its concepts.
- More complex to set up compared to NSTimer and CADisplayLink.
In summary, the choice of timer depends on the specific requirements of your application. If you need high precision and real-time timing, dispatch_source_t is a good option. If you are working with UI-related tasks and smooth animations, CADisplayLink is suitable. NSTimer is a simpler option but may not provide the same level of precision as the other two timers.
Learn more: