单例用于带有xib的UIViewController

时间:2014-04-19 12:03:21

标签: ios uiviewcontroller singleton static-methods

由于我的应用程序有多个LoginViewController没有意义,我尝试将单例模式与initWithNibName结合起来,如下所示:

+ (instancetype)sharedInstance {
    static id sharedInstance;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedInstance = [super initWithNibName:@"LoginViewController" bundle:nil];
    });
    return sharedInstance;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    NSLog(@"ignoring initWithNibName and calling sharedInstance");

//    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
//    if (self) {
//
//    }

    return [LoginViewController sharedInstance];
}

问题是该行:

sharedInstance = [super initWithNibName:@"LoginViewController" bundle:nil];

给我这个错误:

No known class method for selector 'initWithNibName:bundle:'

那么,如果通常在initWithNibName:bundle中调用完全相同的代码,情况会怎样?我怀疑它是因为sharedInstance是一个静态方法,并且UIViewController没有initWithNibName:bundle的静态方法。

仍然,我想知道是否有办法绕过它,因为我不想每次需要使用它时都不必创建一个LoginViewController。

我也希望防止调用LoginViewController initWithNibName:bundle:并获取单独的实例。

1 个答案:

答案 0 :(得分:4)

+sharedInstance是一个类方法,所以在它内部self求值为类LoginViewControllersuper指向类UIViewController。 -initWithNibNamed:bundle:是一种实例方法。

static LoginViewController *sharedInstance;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if(sharedInstance) {
        // avoid creating more than one instance
        [NSException raise:@"bug" format:@"tried to create more than one instance"];
    }

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self) {
        // own initialization code here
    }
    return self;
}

+ (LoginViewController *)sharedInstance
{
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedInstance = [[LoginViewController alloc] initWithNibName:@"LoginViewController" bundle:nil];
    });
    return sharedInstance;
}

-init方法系列存在隐式契约,表明alloc + init应始终返回一个新对象或一个在语义上与新对象无法区分的对象。例如。 [NSNumber numberWithInt:2]并不一定要总是返回一个新对象,因为不需要区分两个不同的对象。

因此,您有两种选择:1)如果有人尝试创建其他LoginViewController或2)允许创建其他LoginViewController,则引发异常。第三个选项(3)只是返回sharedInstance,如果有人试图创建一个新的LoginViewController)打破了初始化的契约,这意味着它会向调用者返回一些他没想到的东西!如果调用者知道LoginViewController是单例,他应该使用+sharedInstance。如果调用者不知道它,他应该获得异常或获得一个新的LoginViewController。