我们有一个子类NSNotificationQueue
,该子类具有一些自定义方法,这些方法在dispatch_async
调用中加入一个通知,以便退出主线程。
我们有一个类方法sharedQueue
,该方法使用dispatch_once
和静态引用返回平均的Objective-C样式单例。
我的问题是,如果我们从后台线程调用sharedQueue
方法是那个单例然后绑定到后台线程,并且该线程消失了,单例也会被删除吗?如果是这样,我们是否应该确保在主线程上创建单例?
如果需要确保在主线程上创建单例,这是我们的方法:
+ (instancetype)sharedQueue
{
static dispatch_once_t onceToken;
static BCOVNotificationQueue *notificationQueue;
dispatch_once(&onceToken, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
notificationQueue = [[BCOVNotificationQueue alloc] initWithNotificationCenter:NSNotificationCenter.defaultCenter];
});
});
return notificationQueue;
}
答案 0 :(得分:1)
创建线程安全的单例的正确方法是什么?
技术很简单:
+ (instancetype)sharedQueue {
static dispatch_once_t onceToken;
static BCONotificationQueue *sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[BCONotificationQueue alloc] init];
});
return sharedInstance;
}
这是单例的标准,线程安全的实例。
但是你说:
我们有一个子类
NSNotificationQueue
...
这说明了您将其分配到主队列的直觉(因为您正在处理NSNotificationQueue
,并且特别是您对哪个线程进行了调用)。但是,您不希望将您的单身人士同步分派到主队列。我建议您将单例本身的实例化(使用上述模式)与所需的NSNotificationQueue
分开。
让我们假设一秒钟,您的意图是发布到主线程,无论您在何处调用BCONotificationQueue
。您不必将其子类化为NSNotificationQueue
,而只需使其成为不透明的NSObject
,其私有实现将基础NSNotificationQueue
包裹起来,如下所示:
// BCONotificationQueue.h
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
@interface BCONotificationQueue: NSObject
@property (class, readonly) BCONotificationQueue *sharedQueue NS_SWIFT_NAME(shared);
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle;
@end
NS_ASSUME_NONNULL_END
和
// BCONotificationQueue.m
#import "BCONotificationQueue.h"
@interface BCONotificationQueue ()
@property (nonatomic, strong) NSNotificationQueue *queue;
@end
@implementation BCONotificationQueue
+ (BCONotificationQueue *)sharedQueue {
static dispatch_once_t onceToken;
static BCONotificationQueue *sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[BCONotificationQueue alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
if ((self = [super init])) {
dispatch_async(dispatch_get_main_queue(), ^{
self.queue = [[NSNotificationQueue alloc] initWithNotificationCenter:NSNotificationCenter.defaultCenter];
});
}
return self;
}
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle {
dispatch_async(dispatch_get_main_queue(), ^{
[self.queue enqueueNotification:notification postingStyle:postingStyle];
});
}
@end
因此,我们将像对待Objective-C一样实例化我们的单例,但是在幕后,我们将异步地分派包装的NSNotificationQueue
的实例化(避免任何死锁风险)到主队列。包装的enqueueNotification
将执行相同的操作,以确保所有通知队列操作都在主(串行)队列上进行,同时仍然享受BCONotificationQueue
包装器的单例行为。