Как обеспечить потокобезопасное использование "NSCalendar currentCalendar"? - PullRequest
3 голосов
/ 01 марта 2012

Согласно Apple Docs NSCalendar не является поточно-ориентированным . Как я могу обеспечить безопасность потоков, когда я использую статический метод currentCalendar?

Любая библиотека может вызывать один и тот же метод. Как я могу заблокировать доступ?

Ответы [ 3 ]

0 голосов
/ 01 марта 2012

Я ожидаю, что создание Календаря будет поточно-ориентированным (каждый раз, когда вызывается -currentCalendar, вы получаете новый экземпляр), одновременное изменение экземпляра не будет.

0 голосов
/ 20 июля 2015

Возможно, вы захотите использовать прокси, чтобы обернуть все методы в синхронизированный блок.Смотрите мой класс 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
0 голосов
/ 01 марта 2012

Вы можете использовать NSLock.

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

и

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