Apple Docsによると、NSCalendarはスレッドセーフではありません。静的メソッドcurrentCalendar
を使用する場合、どうすればスレッドセーフを確保できますか?
どのライブラリでも同じメソッドを呼び出すことができます。アクセスをロックするにはどうすればよいですか?
Apple Docsによると、NSCalendarはスレッドセーフではありません。静的メソッドcurrentCalendar
を使用する場合、どうすればスレッドセーフを確保できますか?
どのライブラリでも同じメソッドを呼び出すことができます。アクセスをロックするにはどうすればよいですか?
NSLockを使用できます。
NSLock *lock = [[NSLock alloc] init];
と
[lock lock];
//calendar
[lock unlock];
カレンダーの作成はスレッドセーフであり(-currentCalendarが呼び出されるたびに、新しいインスタンスを取得します)、同時にインスタンスを変更することはできません。
プロキシを使用して、同期されたブロック内のすべてのメソッドをラップすることをお勧めします。以下の私のクラスBMProxyを参照してください(threadSafeがYESに設定されています)。このクラスを使用して、NSDateFormattersとNSCalendarsを複数のスレッドで再利用します。これは魅力のように機能します。他の非スレッドセーフクラスのインスタンスにも使用できます。
使用法は、たとえば次のとおりです。
+ (NSCalendar *)threadSafeCalendar {
static NSCalendar *calender = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSCalendar *c = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[c setTimeZone:[NSTimeZone timeZoneWithName:@"CET"]];
calender = (NSCalendar *)[BMProxy proxyWithObject:c threadSafe:YES retained:YES];
});
return calender;
}
BMProxyクラス:
#import <Foundation/Foundation.h>
/**
Proxy that delegates all messages to the specified object
*/
@interface BMProxy : NSProxy {
@private
__weak NSObject *_object;
__strong NSObject *_retainedObject;
BOOL _threadSafe;
}
/**
The target object of the proxy.
*/
@property(readonly, weak) NSObject *object;
/**
Whether the proxy should be thread-safe (make all methods synchronized) or not.
*/
@property(atomic, assign) BOOL threadSafe;
/**
Initializer with the designated target object.
Defaults to threadSafe = NO and retained = YES.
@param object The proxied object
*/
- (id)initWithObject:(NSObject *)object;
/**
Initializer with the designated target object and whether the proxy should be thread-safe or not.
Defaults to retained = YES.
@param object The proxied object
@param threadSafe Whether the proxy should synchronize all methods or not.
*/
- (id)initWithObject:(NSObject *)object threadSafe:(BOOL)threadSafe;
/**
Designated initializer.
The retained parameter determines whether the target object is retained or not.
*/
- (id)initWithObject:(NSObject *)object threadSafe:(BOOL)threadSafe retained:(BOOL)retained;
+ (BMProxy *)proxyWithObject:(NSObject *)object threadSafe:(BOOL)threadSafe retained:(BOOL)retained;
@end
@implementation BMProxy
@synthesize threadSafe = _threadSafe;
@synthesize object = _object;
+ (BMProxy *)proxyWithObject:(NSObject *)object threadSafe:(BOOL)threadSafe retained:(BOOL)retained {
return [[BMProxy alloc] initWithObject:object threadSafe:threadSafe retained:retained];
}
- (id)initWithObject:(NSObject *)theObject {
return [self initWithObject:theObject threadSafe:NO retained:YES];
}
- (id)initWithObject:(NSObject *)theObject threadSafe:(BOOL)b {
return [self initWithObject:theObject threadSafe:b retained:YES];
}
- (id)initWithObject:(NSObject *)theObject threadSafe:(BOOL)b retained:(BOOL)retained {
_object = theObject;
if (retained) {
_retainedObject = theObject;
}
self.threadSafe = b;
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [_object methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
if (self.threadSafe) {
@synchronized(_object) {
[anInvocation setTarget:_object];
[anInvocation invoke];
}
} else {
[anInvocation setTarget:_object];
[anInvocation invoke];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL responds = [super respondsToSelector:aSelector];
if (!responds) {
responds = [_object respondsToSelector:aSelector];
}
return responds;
}
@end