Es posible hacer que un guión gráfico cree una instancia de diferentes subclases de un controlador de vista personalizado, aunque implica una técnica ligeramente poco ortodoxa: anular el allocmétodo para el controlador de vista. Cuando se crea el controlador de vista personalizado, el método alloc anulado de hecho devuelve el resultado de la ejecución allocen la subclase.
Debo comenzar la respuesta con la condición de que, aunque lo probé en varios escenarios y no recibí errores, no puedo asegurar que se adapte a configuraciones más complejas (pero no veo ninguna razón por la que no debería funcionar) . Además, no he enviado ninguna aplicación con este método, por lo que existe la posibilidad de que sea rechazada por el proceso de revisión de Apple (aunque, nuevamente, no veo ninguna razón por la que debería hacerlo).
Para fines de demostración, tengo una subclase de UIViewControllercalled TestViewController, que tiene un UILabel IBOutlet y un IBAction. En mi guión gráfico, agregué un controlador de vista y modifiqué su clase TestViewControllery conecté IBOutlet a un UILabel y IBAction a un UIButton. Presento el TestViewController mediante un segue modal desencadenado por un UIButton en el viewController anterior.

Para controlar qué clase se instancia, he agregado una variable estática y métodos de clase asociados, así que obtenga / configure la subclase que se utilizará (supongo que se podrían adoptar otras formas de determinar qué subclase se instanciará):
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];
}
}
}
Para mi prueba tengo dos subclases de TestViewController: RedTestViewControllery GreenTestViewController. Cada una de las subclases tiene propiedades adicionales y cada una se reemplaza viewDidLoadpara cambiar el color de fondo de la vista y actualizar el texto de 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";
}
En algunas ocasiones podría querer crear TestViewControlleruna instancia de sí mismo, en otras ocasiones RedTestViewControllero GreenTestViewController. En el controlador de vista anterior, hago esto al azar de la siguiente manera:
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"];
}
Tenga en cuenta que el setClassForStoryBoardmétodo verifica para asegurarse de que el nombre de clase solicitado sea de hecho una subclase de TestViewController, para evitar confusiones. La referencia anterior a BlueTestViewControllerestá ahí para probar esta funcionalidad.