如何确保线程安全使用“NSCalendar currentCalendar”?

时间:2012-03-01 14:39:47

标签: ios macos thread-safety static-methods nscalendar

根据Apple Docs NSCalendar is not thread-safe。 使用static method currentCalendar时,如何确保线程安全?

任何库都可以调用相同的方法。如何锁定访问权限?

3 个答案:

答案 0 :(得分:0)

您可以使用NSLock。

NSLock *lock = [[NSLock alloc] init];

[lock lock];
//calendar
[lock unlock];

答案 1 :(得分:0)

我希望创建一个Calendar是线程安全的(每次调用-currentCalendar你得到一个新实例),同时变异实例不会。

答案 2 :(得分:0)

您可能希望使用代理来包装同步块中的所有方法。请参阅下面的我的类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