【问题标题】:How to ensure thread-safe use of "NSCalendar currentCalendar"?如何确保“NSCalendar currentCalendar”的线程安全使用?
【发布时间】:2012-03-01 14:39:46
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    您可以使用 NSLock。

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

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

    【讨论】:

    • 是的。我可以使用锁来自己使用该功能。但是如果一个库或任何“不是我的代码”的东西正在使用该方法呢?
    • “不是你的代码”不应该关心自己吗?只需在文档中说明您的方法不是线程安全的。毕竟苹果这样做了。
    【解决方案2】:

    我希望创建日历是线程安全的(每次调用 -currentCalendar 时都会获得一个新实例),同时改变一个实例不会。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-27
        • 1970-01-01
        • 2014-10-26
        • 1970-01-01
        相关资源
        最近更新 更多