เป็นไปได้ที่จะมีสตอรี่บอร์ดสร้างอินสแตนซ์คลาสย่อยที่แตกต่างกันของตัวควบคุมมุมมองที่กำหนดเองแม้ว่าจะเกี่ยวข้องกับเทคนิคนอกรีตเล็กน้อย: การแทนที่alloc
เมธอดสำหรับตัวควบคุมมุมมอง เมื่อสร้างตัวควบคุมมุมมองแบบกำหนดเองเมธอดการจัดสรรที่ถูกแทนที่ในความเป็นจริงจะส่งคืนผลลัพธ์ของการรันalloc
บนคลาสย่อย
ฉันควรนำคำตอบด้วยเงื่อนไขที่ว่าแม้ว่าฉันได้ทดสอบในสถานการณ์ต่างๆและไม่ได้รับข้อผิดพลาด แต่ฉันไม่สามารถมั่นใจได้ว่าจะรับมือกับการตั้งค่าที่ซับซ้อนมากขึ้น (แต่ฉันไม่เห็นเหตุผลว่าทำไมจึงไม่ควรทำงาน) . นอกจากนี้ฉันยังไม่ได้ส่งแอพใด ๆ โดยใช้วิธีนี้ดังนั้นจึงมีโอกาสภายนอกที่กระบวนการตรวจสอบของ Apple อาจถูกปฏิเสธ (อีกครั้งฉันไม่เห็นเหตุผลว่าทำไมถึงควร)
เพื่อวัตถุประสงค์ในการสาธิตฉันมีคลาสย่อยของการUIViewController
เรียกTestViewController
ซึ่งมี UILabel IBOutlet และ IBAction ในสตอรีบอร์ดของฉันฉันได้เพิ่มตัวควบคุมมุมมองและแก้ไขคลาสของมันTestViewController
และเชื่อมต่อ IBOutlet กับ UILabel และ IBAction เข้ากับ UIButton ฉันนำเสนอ TestViewController โดยใช้ modal segue ที่เรียกใช้โดย 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
เพื่อเปลี่ยนสีพื้นหลังของมุมมองและอัปเดตข้อความของ 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
มีไว้เพื่อทดสอบฟังก์ชันนี้