我想知道重置dispatch_once是否安全(不涉及线程):
我的情况是整个应用程序我缓存NSDateFormatters
和NSNumberFormatters
等。我是通过将它们包裹在dispatch_once
次调用中来实现的。
现在当我收到区域设置发生变化的NSNotification时,id就像重置了一些dispatch_once标记,所以下次需要格式化时,它们会再次分配。
我只是让每个vc观察通知并将标记的值重置为0.
这样可以吗?感觉......一方面有点脏,但也可以,因为替代方案是使用BOOLS并用if ...替换调度调用。
#import "ViewController.h"
static dispatch_once_t onceToken;
@implementation ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
[[NSNotificationCenter defaultCenter] addObserverForName:NSCurrentLocaleDidChangeNotification
object:self
queue:nil
usingBlock:^(NSNotification *note) {
onceToken = 0;
}
}
//image this called every second...
- (void)viewDidAppear:(BOOL)animated {
//need a for matter only here
static NSDateFormatter *formatter;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
});
NSLog(@"%@", [formatter stringFromDate:[NSDate date]]);
}
@end
答案 0 :(得分:3)
The documentation of dispatch_once明确指出:"只执行一次"。
只要您想多次运行一个块,就不要使用dispatch_once。你也已经对它感到肮脏了。
相反,你应该运行这样的代码:
static NSDateFormatter *sharedDateFormatter; // already initialized to nil
+ (NSDateFormatter *)sharedDateFormatter
{
if (sharedDateFormatter == nil) {
sharedDateFormatter = ...;
}
return sharedDateFormatter;
}
// should be called when relevant NSNotification occur.
+ (void)resetSharedDateFormatter
{
sharedDateFormatter = nil;
}
附注:请注意NSDateFormatter不是线程安全的:如果在不同的线程中使用单个实例,则可能会遇到崩溃。如果可以的话,你最好坚持主线程。或者每个线程有不同的实例。但这超出了你的问题。
答案 1 :(得分:2)
dispatch_once单例模型用于提供线程安全性。如果你肯定只会从主UI线程访问单例(就像在这种情况下似乎那样),没有充分的理由不回到旧的单例模型:
static NSDateFormatter* myFormatter;
+(NSDateFormatter*)mySingletonFormatter
{
if(!myFormatter)
{
myFormatter = [...];
}
return myFormatter;
}
+(void)resetMyFormatter
{
myFormatter = nil;
}
如果必须同时执行这两项操作(在多线程环境中重置),则可以包装格式化程序创建并在@synchronized(self)中重置。
我会避免修改dispatch_once_t的私有位,因为它没有记录它的使用方式(虽然它暗示将其重置为0会清除它,但它没有记录。)为了保持线程安全,无论如何你都必须将整个东西包裹在信号量中,所以不妨回到已知的文档化解决方案。