Можливо, щоб дошка розкадрувала примірник різних підкласів користувацького контролера перегляду, хоча це включає дещо неортодоксальну техніку: переосмислення alloc
методу для контролера перегляду. Коли створений спеціальний контролер перегляду, метод перекритого аллока фактично повертає результат запуску alloc
на підкласі.
Я повинен передмовити відповідь за умови, що, хоч я перевіряв її в різних сценаріях і не отримував помилок, я не можу гарантувати, що він впорається зі складнішими налаштуваннями (але я не бачу причини, чому він не повинен працювати) . Крім того, я не надсилав жодних додатків за допомогою цього методу, тому існує ймовірність, що він може бути відхилений процесом перегляду Apple (хоча, знову ж таки, я не бачу причин, чому це потрібно).
Для демонстраційних цілей, у мене є підклас UIViewController
під назвою TestViewController
, яке має UILabel IBOutlet, і IBAction. У моєму розкладі я додав контролер перегляду та змінив його клас на TestViewController
та підключив IBOutlet до UILabel, а IBAction - до UIButton. Я представляю TestViewController за допомогою модальної розвідки, ініційованої UIButton на попередньому viewController.
Для контролю того, який клас є інстанційним, я додав статичну змінну та пов'язані з ними методи класу, тому отримайте / встановіть підклас, який буде використовуватися (я думаю, можна було б прийняти інші способи визначення, який підклас повинен бути ініційований):
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
для зміни кольору фону подання та оновлення тексту IBOutlet UILabel:
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
це є для перевірки цієї функціональності.