可以让故事板实例化自定义视图控制器的不同子类,尽管它涉及一种稍微不正统的技术:覆盖alloc
视图控制器的方法。创建自定义视图控制器时,被覆盖的 alloc 方法实际上返回的是alloc
在子类上运行的结果。
我应该以附带条件作为答案的开头,尽管我已经在各种场景中对其进行了测试并且没有收到任何错误,但我无法确保它能够应对更复杂的设置(但我认为它没有理由不工作) . 此外,我还没有使用这种方法提交任何应用程序,因此它可能会被 Apple 的审核流程拒绝(尽管我再次认为没有理由这样做)。
出于演示目的,我有一个UIViewController
called的子类TestViewController
,它有一个 UILabel IBOutlet 和一个 IBAction。在我的故事板中,我添加了一个视图控制器并将其类修改为TestViewController
,并将 IBOutlet 连接到 UILabel 并将 IBAction 连接到 UIButton。我通过由前一个 viewController 上的 UIButton 触发的模态 segue 来呈现 TestViewController。
为了控制实例化哪个类,我添加了一个静态变量和关联的类方法,以便获取/设置要使用的子类(我想可以采用其他方法来确定要实例化哪个子类):
测试视图控制器.m:
#import "TestViewController.h"
@interface TestViewController ()
@end
@implementation TestViewController
static NSString *_classForStoryboard;
+(NSString *)classForStoryboard {
return [_classForStoryboard copy];
}
+(void)setClassForStoryBoard:(NSString *)classString {
if ([NSClassFromString(classString) isSubclassOfClass:[self class]]) {
_classForStoryboard = [classString copy];
} else {
NSLog(@"Warning: %@ is not a subclass of %@, reverting to base class", classString, NSStringFromClass([self class]));
_classForStoryboard = nil;
}
}
+(instancetype)alloc {
if (_classForStoryboard == nil) {
return [super alloc];
} else {
if (NSClassFromString(_classForStoryboard) != [self class]) {
TestViewController *subclassedVC = [NSClassFromString(_classForStoryboard) alloc];
return subclassedVC;
} else {
return [super alloc];
}
}
}
对于我的测试,我有两个子类TestViewController
:RedTestViewController
和GreenTestViewController
. 每个子类都有额外的属性,并且每个覆盖都viewDidLoad
可以更改视图的背景颜色并更新 UILabel IBOutlet 的文本:
RedTestViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
self.testLabel.text = @"Set by RedTestVC";
}
GreenTestViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor greenColor];
self.testLabel.text = @"Set by GreenTestVC";
}
在某些情况下,我可能想实例化TestViewController
自己,在其他情况下RedTestViewController
或GreenTestViewController
. 在前面的视图控制器中,我随机执行如下操作:
NSInteger vcIndex = arc4random_uniform(4);
if (vcIndex == 0) {
NSLog(@"Chose TestVC");
[TestViewController setClassForStoryBoard:@"TestViewController"];
} else if (vcIndex == 1) {
NSLog(@"Chose RedVC");
[TestViewController setClassForStoryBoard:@"RedTestViewController"];
} else if (vcIndex == 2) {
NSLog(@"Chose BlueVC");
[TestViewController setClassForStoryBoard:@"BlueTestViewController"];
} else {
NSLog(@"Chose GreenVC");
[TestViewController setClassForStoryBoard:@"GreenTestViewController"];
}
请注意,该setClassForStoryBoard
方法检查以确保所请求的类名确实是 TestViewController 的子类,以避免任何混淆。上面的参考BlueTestViewController
是为了测试这个功能。