带参数iOS的Singleton

时间:2015-02-21 04:39:17

标签: ios objective-c design-patterns singleton

我需要实现一个接受参数的单例类。每次都会将相同的对象作为参数传递,因此生成的单例对象将始终相同。

我正在做类似下面的代码。这看起来不错吗?有没有更好的方法来实现我想要实现的目标?

  - (id)sharedInstanceWithAccount:(UserAccount *)userAccount {
      if (!sharedInstance) {
        @synchronized(self) {
          sharedInstance = [[[self class] alloc] initWithAccount:userAccount];
        }
      }

      return sharedInstance;
    }

    - (id)initWithAccount:(UserAccount *)userAccount {
      self = [super init];
      if (self) {
        _userAccount = userAccount;
      }

      return self;
    }

    - (id)init {
      NSAssert(false,
               @"You cannot init this class directly. It needs UserAccountDataSource as a paramter");
      return nil;
    }

    + (id)alloc {
      @synchronized(self) {
        NSAssert(sharedInstance == nil, @"Attempted to allocated a second instance of the singleton");
        sharedInstance = [super alloc];
        return sharedInstance;
      }
      return nil;
    }

2 个答案:

答案 0 :(得分:2)

此设计存在许多问题:

  1. 根据Apple的建议,对于单身人士应该dispatch_once而不是@synchronized(self)

    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
         sharedInstance = [[MyClass alloc] init];
         // Do any other initialisation stuff here
    });
    return sharedInstance;
    

    有关详细信息,请参阅此问题:Why does Apple recommend to use dispatch_once for implementing the singleton pattern under ARC?

  2. 错误的API设计将单身人士放入alloc

    如方法alloc的名称所示,这意味着将分配一些内存。但是,在你的情况下,它不是。这种覆盖alloc的尝试将导致团队中其他程序员的混淆。

  3. NSAssert中使用-init的好主意。

    如果要禁用方法,请将其放入头文件中以禁用它:

    - (id)init __attribute__((unavailable)); 
    

    在这种情况下,您将收到编译错误,而不是在运行时崩溃应用程序。 有关更多详细信息,请参阅此帖子:Approach to overriding a Core Data property: isDeleted

    此外,您甚至可以添加不可用的消息:

    - (id)init __attribute__((unavailable("You cannot init this class directly. It needs UserAccountDataSource as a parameter")));
    
  4. 有时会忽略输入参数而不会发出警告。

    在下面的代码中,如果该类的实例已由其他人创建,那么调用此函数的程序员如何知道输入参数userAccount有时会被忽略?

    - (id)sharedInstanceWithAccount:(UserAccount *)userAccount {
        if (!sharedInstance) {
            @synchronized(self) {
               sharedInstance = [[[self class] alloc] initWithAccount:userAccount];
            }
        }
        return sharedInstance;
    }
    
  5. 简而言之,不要认为使用参数创建单例是个好主意。使用传统的单件设计更加清洁。

答案 1 :(得分:0)

objA = [Object sharedInstanceWithAccount:A];
objB = [Object sharedInstanceWithAccount:B];

B被忽略。 objB中的userAccount是A。

如果objB中的userAccount B,您将更改sharedInstanceWithAccount。

- (id)sharedInstanceWithAccount:(UserAccount *)userAccount {
    static NSMutableDictionary *instanceByAccount = [[NSMutableDictionary alloc] init];
    id instance = instanceByAccount[userAccount];

    if (!instance) {
        @synchronized(self) {
            instance = [[[self class] alloc] initWithAccount:userAccount];
            instanceByAccount[userAccount] = instance;
        }
    }

    return instance;
}