एकाधिक उपवर्ग के लिए एकल स्टोरीबोर्ड uiviewcontroller का उपयोग कैसे करें


118

मान लीजिए कि मेरे पास एक स्टोरीबोर्ड है जिसमें UINavigationControllerप्रारंभिक दृश्य नियंत्रक के रूप में है। इसका रूट व्यू कंट्रोलर उपवर्ग है UITableViewController, जो है BasicViewController। इसमें IBActionनेविगेशन बार के सही नेविगेशन बटन से जुड़ा है

। वहां से मैं अतिरिक्त स्टोरीबोर्ड बनाने के बिना स्टोरीबोर्ड को अन्य दृश्यों के लिए टेम्पलेट के रूप में उपयोग करना चाहूंगा। कहें कि इन विचारों में बिल्कुल समान इंटरफ़ेस होगा, लेकिन क्लास के रूट व्यू कंट्रोलर SpecificViewController1और SpecificViewController2जो कि उपवर्ग हैं BasicViewController
उन 2 दृश्य नियंत्रकों में IBActionविधि को छोड़कर समान कार्यक्षमता और इंटरफ़ेस होगा ।
यह निम्नलिखित की तरह होगा:

@interface BasicViewController : UITableViewController

@interface SpecificViewController1 : BasicViewController

@interface SpecificViewController2 : BasicViewController

क्या मैं ऐसा कुछ कर सकता हूं?
क्या मैं सिर्फ स्टोरीबोर्ड को इंस्टेंट कर सकता हूं, BasicViewControllerलेकिन उपवर्ग के लिए रूट व्यू कंट्रोलर है SpecificViewController1और SpecificViewController2?

धन्यवाद।


3
यह इंगित करने के लायक हो सकता है कि आप निब के साथ ऐसा कर सकते हैं। लेकिन अगर आप मेरे जैसे हैं जो कुछ अच्छी सुविधाएँ चाहते हैं जो केवल स्टोरीबोर्ड में हैं (उदाहरण के लिए स्थैतिक / प्रोटोटाइप सेल), तो मुझे लगता है कि हम भाग्य से बाहर हैं।
जोसेफ लिन

जवाबों:


57

महान सवाल - लेकिन दुर्भाग्य से केवल एक लंगड़ा जवाब है। मुझे विश्वास नहीं है कि वर्तमान में ऐसा करना संभव है जो आप प्रस्तावित करते हैं क्योंकि यूआईसटोरीबोर्ड में कोई इनिशियलाइज़र नहीं हैं जो स्टोरीबोर्ड से जुड़े व्यू कंट्रोलर को ओवरराइड करने की अनुमति देते हैं जैसा कि स्टोरीबोर्ड पर ऑब्जेक्ट विवरण में इनिशियलाइज़ेशन में परिभाषित किया गया है। यह आरंभ में है कि स्टोयबोर्ड में सभी UI तत्व व्यू कंट्रोलर में उनके गुणों से जुड़े होते हैं।

यह डिफ़ॉल्ट रूप से दृश्य नियंत्रक के साथ आरंभ करेगा जो स्टोरीबोर्ड परिभाषा में निर्दिष्ट है।

यदि आप स्टोरीबोर्ड में आपके द्वारा बनाए गए UI तत्वों का पुन: उपयोग करने का प्रयास कर रहे हैं, तो उन्हें अभी भी उन संपत्तियों से जुड़ा या जुड़ा होना चाहिए, जिसमें कभी-कभी नियंत्रक उन्हें घटनाओं के बारे में दृश्य नियंत्रक को "बताने" में सक्षम होने के लिए उनका उपयोग कर रहे हैं।

ऐसा नहीं है कि स्टोरीबोर्ड लेआउट पर नकल करना बहुत बड़ी बात है, खासकर यदि आपको केवल 3 दृश्यों के लिए एक समान डिज़ाइन की आवश्यकता है, हालांकि यदि आप करते हैं, तो आपको यह सुनिश्चित करना होगा कि पिछले सभी संघों को मंजूरी दे दी गई है, या यह कोशिश करने पर क्रैश हो जाएगा पिछले दृश्य नियंत्रक से संवाद करने के लिए। आप उन्हें लॉग आउटपुट में KVO त्रुटि संदेशों के रूप में पहचान सकेंगे।

कुछ दृष्टिकोण जो आप अपना सकते हैं:

  • यूआईवीयू में यूआई तत्वों को स्टोर करें - एक एक्सिब फाइल में और इसे अपने बेस क्लास से इंस्टेंट करें और इसे मुख्य दृश्य में उप दृश्य के रूप में जोड़ें, आमतौर पर स्व.विव्यू। तब आप बस स्टोरीबोर्ड लेआउट का उपयोग मूल रूप से रिक्त दृश्य नियंत्रकों के साथ स्टोरीबोर्ड में अपनी जगह रखने के लिए करेंगे, लेकिन सही दृश्य नियंत्रक उप वर्ग के साथ उन्हें सौंपा जाएगा। चूंकि वे आधार से वारिस होंगे, उन्हें वह दृश्य मिलेगा।

  • कोड में लेआउट बनाएं और इसे अपने बेस व्यू कंट्रोलर से इंस्टॉल करें। जाहिर है कि यह दृष्टिकोण स्टोरीबोर्ड का उपयोग करने के उद्देश्य को पराजित करता है, लेकिन आपके मामले में जाने का तरीका हो सकता है। यदि आपके पास ऐप के अन्य भाग हैं जो स्टोरीबोर्ड दृष्टिकोण से लाभान्वित होंगे, तो उपयुक्त होने पर यहां और वहां विचलन करना ठीक है। इस मामले में, ऊपर की तरह, आप बस अपने उपवर्ग के साथ बैंक व्यू कंट्रोलर का उपयोग करेंगे और बेस व्यू कंट्रोलर को यूआई स्थापित करने दें।

यह अच्छा होगा यदि Apple आपके प्रस्तावित करने के तरीके के साथ आए, लेकिन नियंत्रक उपवर्ग के साथ पहले से जुड़े ग्राफिक तत्वों के होने का मुद्दा अभी भी एक मुद्दा होगा।

आपका नया साल शानदार हो!! खुश रहो


यह जल्दी था। जैसा कि मैंने सोचा था, यह संभव नहीं होगा। वर्तमान में मैं सिर्फ उस BasicViewController क्लास होने से एक समाधान के साथ आता हूं और यह इंगित करने के लिए अतिरिक्त संपत्ति है कि "क्लास" / "मोड" के रूप में कार्य करेगा। फिर भी धन्यवाद।
वर्डी

2
बहुत बुरा :( मुझे लगता है कि मुझे एक ही व्यू कंट्रोलर को कॉपी और पेस्ट करना है और अपनी क्लास को वर्कअराउंड के रूप में बदलना है।
Hlung

1
और यही कारण है कि मुझे स्टोरीबोर्ड पसंद नहीं है ... किसी भी तरह वे वास्तव में एक बार काम नहीं कर रहे हैं जब आप मानक विचारों से थोड़ा अधिक करते हैं ...
10

इतना दुखी जब आपने कहा कि सुनकर। मैं समाधान के लिए देख रहा हूँ
टोनी

2
एक और दृष्टिकोण है: अलग-अलग प्रतिनिधियों में कस्टम तर्क निर्दिष्ट करें और तैयारी में, सही प्रतिनिधि असाइन करें। इस तरह, आप स्टोरीबोर्ड में 1 UIViewController + 1 UIViewController बनाते हैं लेकिन आपके पास कई कार्यान्वयन संस्करण हैं।
plam4u

45

हम जिस लाइन की तलाश में हैं, वह है:

object_setClass(AnyObject!, AnyClass!)

स्टोरीबोर्ड में -> UIViewController जोड़ें यह एक ParentVC वर्ग का नाम देता है।

class ParentVC: UIViewController {

    var type: Int?

    override func awakeFromNib() {

        if type = 0 {

            object_setClass(self, ChildVC1.self)
        }
        if type = 1 {

            object_setClass(self, ChildVC2.self)
        }  
    }

    override func viewDidLoad() {   }
}

class ChildVC1: ParentVC {

    override func viewDidLoad() {
        super.viewDidLoad()

        println(type)
        // Console prints out 0
    }
}

class ChildVC2: ParentVC {

    override func viewDidLoad() {
        super.viewDidLoad()

        println(type)
        // Console prints out 1
    }
}

5
धन्यवाद, यह सिर्फ काम करता है, उदाहरण के लिए:class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
कोकोआ

3
मुझे यकीन नहीं है कि मैं समझता हूं कि यह कैसे काम करना चाहिए। माता-पिता अपनी कक्षा को एक बच्चे के रूप में स्थापित कर रहे हैं? फिर आपके कई बच्चे कैसे हो सकते हैं ?!
user1366265

2
सर, आपने मेरा दिन बना दिया है
jere

2
ठीक है दोस्तों, इसलिए मुझे इसे थोड़ा और विस्तार से बताएं: हम क्या हासिल करना चाहते हैं? हम अपने ParentViewController को उप-वर्ग करना चाहते हैं ताकि हम इसके स्टोरीबोर्ड को अधिक कक्षाओं के लिए उपयोग कर सकें। तो जादू लाइन जो यह सब करती है वह मेरे समाधान में हाइलाइट की गई है और पेरेंटव्यू में awakeFromNib में उपयोग की जानी चाहिए। तब क्या होता है कि यह नए सेट चाइल्डव्यू 1 से सभी विधियों का उपयोग करता है जो एक उपवर्ग के रूप में बन जाता है। यदि आप इसे अधिक चाइल्डवॉक्स के लिए उपयोग करना चाहते हैं? बस awakeFromNib में अपना तर्क दें।
जिआह ज़ाल्का

10
इसका उपयोग करते समय बहुत सावधान रहें! आम तौर पर यह बिल्कुल भी इस्तेमाल नहीं किया जाना चाहिए ... यह बस दिए गए पॉइंटर के आइसा पॉइंटर को बदलता है और उदाहरण के लिए विभिन्न गुणों के लिए समायोजित करने के लिए मेमोरी को फिर से व्यवस्थित नहीं करता है। इसके लिए एक संकेतक यह है कि सूचक selfनहीं बदलता है। तो ऑब्जेक्ट का निरीक्षण (उदाहरण के लिए _ivar / संपत्ति मान पढ़ना) के बाद object_setClassक्रैश हो सकता है।
पैट्रिक

15

जैसा कि स्वीकृत उत्तर बताता है, ऐसा नहीं लगता है कि स्टोरीबोर्ड के साथ ऐसा करना संभव है।

मेरा समाधान निब का उपयोग करना है - जैसे कि स्टोरीबोर्ड से पहले देवों ने उनका उपयोग किया था। यदि आप एक पुन: प्रयोज्य, अवचेतन दृश्य नियंत्रक (या यहां तक ​​कि एक दृश्य) चाहते हैं, तो मेरी सिफारिश निब का उपयोग करने की है।

SubclassMyViewController *myViewController = [[SubclassMyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; 

जब आप अपने सभी आउटलेट्स को "फाइल ओनर" से जोड़ते MyViewController.xibहैं , तो आप यह निर्दिष्ट नहीं कर रहे हैं कि निब को किस वर्ग में लोड किया जाना चाहिए, आप केवल कुंजी-मूल्य वाले जोड़े निर्दिष्ट कर रहे हैं: " यह दृश्य इस उदाहरण चर नाम से जुड़ा होना चाहिए ।" [SubclassMyViewController alloc] initWithNibName:आरंभीकरण प्रक्रिया को कॉल करते समय निर्दिष्ट करता है कि आपके द्वारा निब में बनाए गए दृश्य को " नियंत्रित " करने के लिए किस कंट्रोलर का उपयोग किया जाएगा ।


हैरानी की बात यह है कि स्टोरीबोर्ड के साथ यह संभव है, ओबजैक रनटाइम लाइब्रेरी के लिए धन्यवाद। यहाँ मेरे उत्तर की जाँच करें: stackoverflow.com/a/57622836/7183675
एडम टुचोल्स्की

9

एक स्टोरीबोर्ड को कस्टम व्यू कंट्रोलर के अलग-अलग उपवर्गों में इंस्टेंट करना संभव है, हालांकि इसमें थोड़ी अपरंपरागत तकनीक शामिल है: allocव्यू कंट्रोलर के लिए विधि को ओवरराइड करना । जब कस्टम दृश्य नियंत्रक बनाया जाता है, तो ओवरराइड आवंटित विधि वास्तव allocमें उपवर्ग पर चलने का परिणाम देता है ।

मुझे उत्तर को अनंतिम रूप से प्रस्तुत करना चाहिए, हालांकि मैंने इसे विभिन्न परिदृश्यों में परीक्षण किया है और कोई त्रुटि नहीं मिली है, मैं यह सुनिश्चित नहीं कर सकता कि यह अधिक जटिल सेट अप के साथ सामना करेगा (लेकिन मुझे कोई कारण नहीं है कि यह काम क्यों नहीं करना चाहिए) । इसके अलावा, मैंने इस पद्धति का उपयोग करके कोई भी एप्लिकेशन सबमिट नहीं किया है, इसलिए बाहर का मौका है कि इसे Apple की समीक्षा प्रक्रिया द्वारा अस्वीकार किया जा सकता है (हालांकि फिर से मुझे कोई कारण नहीं दिखाई देना चाहिए कि यह क्यों होना चाहिए)।

प्रदर्शन प्रयोजनों के लिए, मेरे पास उप UIViewControllerनाम का एक उपवर्ग है TestViewController, जिसमें एक UILabel IBOutlet और एक IBAction है। अपने स्टोरीबोर्ड में, मैंने एक दृश्य नियंत्रक जोड़ा है और अपनी कक्षा में संशोधन किया है TestViewController, और IBOutlet को एक UILabel और IBAction को एक UIButton तक झुका दिया है। मैं TestViewController को पूर्ववर्ती दृश्य नियंत्रण रेखा पर एक UIButton द्वारा ट्रिगर किए गए एक मोडल सेग के माध्यम से प्रस्तुत करता हूं।

स्टोरीबोर्ड छवि

यह नियंत्रित करने के लिए कि कौन सी कक्षा में त्वरित किया गया है, मैंने एक स्थिर चर और संबद्ध वर्ग विधियाँ जोड़ी हैं, ताकि उपयोग होने के लिए उप-वर्ग प्राप्त करें / निर्धारित करें (मुझे लगता है कि कोई निर्धारित करने के अन्य तरीके अपना सकता है कि उपवर्ग को तत्काल बनाया जाए):

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विधि यह सुनिश्चित करने के लिए जांच करती है कि अनुरोधित वर्ग नाम वास्तव में किसी भी मिश्रण-अप से बचने के लिए टेस्टव्यूकंट्रोलर का उपवर्ग है। BlueTestViewControllerइस कार्यक्षमता का परीक्षण करने के लिए ऊपर संदर्भ है ।


हमने इस परियोजना में कुछ ऐसा ही किया है, लेकिन सभी वर्गों के बारे में पूरी जानकारी इकट्ठा करने वाले बाहरी वर्ग से उपवर्ग प्राप्त करने के लिए UIViewController की आवंटन विधि को ओवरराइड कर रहा है। अच्छी तरह से काम।
टिम

वैसे यह विधि फास आर के रूप में काम करना बंद कर सकती है क्योंकि Apple व्यू कंट्रोलर्स पर कॉल आवंटन को रोकता है। उदाहरण के लिए NSManagedObject वर्ग को आवंटित विधि कभी नहीं मिलती है। मुझे लगता है कि एप्पल एक और तरीका करने के लिए कोड को कॉपी कर सकते हैं: हो सकता है + allocManagedObject
टिम

7

यह कोशिश करें, InstantiateViewControllerWithIdentifier के बाद।

- (void)setClass:(Class)c {
    object_setClass(self, c);
}

पसंद :

SubViewController *vc = [sb instantiateViewControllerWithIdentifier:@"MainViewController"];
[vc setClass:[SubViewController class]];

कृपया अपने कोड के बारे में कुछ उपयोगी विवरण जोड़ें।
कोडवर्डर

7
यदि आप उपवर्ग से उदाहरण चर का उपयोग करते हैं, तो इसके साथ क्या होता है? मैं दुर्घटना का अनुमान लगा रहा हूं, क्योंकि फिट होने के लिए पर्याप्त मेमोरी आवंटित नहीं है। मेरे परीक्षणों में, मुझे लगता रहा है EXC_BAD_ACCESS, इसलिए इसकी सिफारिश नहीं की जा रही है ।
लेगलेस

1
यदि आप चाइल्ड क्लास में नए चर जोड़ेंगे तो यह काम नहीं करेगा। और बच्चे को initभी नहीं बुलाया जाएगा। ऐसे अवरोध सभी दृष्टिकोण को अनुपयोगी बनाते हैं।
अल जोंके

6

विशेष रूप से nicgzzjr और Jií Zahálka पर प्लसिंग के साथ-साथ कोकोआकोबोबा के दूसरे एक के तहत टिप्पणी के आधार पर मैंने लघु जेनेरिक विधि तैयार की है जिसमें ओपी की जरूरत है। आपको केवल स्टोरीबोर्ड नाम और व्यू कंट्रोलर स्टोरीबोर्ड आईडी की जांच करने की आवश्यकता है

class func instantiate<T: BasicViewController>(as _: T.Type) -> T? {
        let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
        guard let instance = storyboard.instantiateViewController(withIdentifier: "Identifier") as? BasicViewController else {
            return nil
        }
        object_setClass(instance, T.self)
        return instance as? T
    }

बल अनट्रैप (स्विफ्टलिंट चेतावनियों) से बचने के लिए विकल्प जोड़े जाते हैं, लेकिन विधि सही ऑब्जेक्ट लौटाती है।


5

हालांकि यह कड़ाई से एक उपवर्ग नहीं है, आप कर सकते हैं:

  1. option-डॉग क्लास व्यू कंट्रोलर को कॉपी बनाने के लिए डॉक्यूमेंट आउटलाइन में देखें
  2. स्टोरीबोर्ड पर एक अलग जगह पर नए व्यू कंट्रोलर कॉपी को स्थानांतरित करें
  3. पहचान निरीक्षक में उपवर्ग दृश्य नियंत्रक में कक्षा बदलें

यहाँ एक से एक उदाहरण है ब्लॉक ट्यूटोरियल मैंने लिखा, उपवर्गीकरण ViewControllerसाथ WhiskeyViewController:

उपरोक्त तीन चरणों का एनीमेशन

यह आपको स्टोरीबोर्ड में व्यू कंट्रोलर उपवर्गों के उपवर्ग बनाने की अनुमति देता है। फिर आप instantiateViewControllerWithIdentifier:विशिष्ट उपवर्ग बनाने के लिए उपयोग कर सकते हैं ।

यह दृष्टिकोण थोड़ा अनम्य है: बाद में स्टोरीबोर्ड से बेस क्लास कंट्रोलर के भीतर संशोधन उपवर्ग के लिए प्रचारित नहीं करते हैं। यदि आपके पास बहुत सारे उपवर्ग हैं, तो आप अन्य समाधानों में से एक के साथ बेहतर हो सकते हैं, लेकिन यह चुटकी में करेगा।


11
यह एक उपवर्गीय दोस्त नहीं है, यह सिर्फ एक ViewController नकल कर रहा है।
ऐस ग्रीन

1
यह सही नहीं है। जब आप क्लास को उपवर्ग (चरण 3) में बदलते हैं तो यह एक उपवर्ग बन जाता है । फिर आप जो भी बदलाव करना चाहते हैं, कर सकते हैं और अपने उपवर्ग में आउटलेट / कार्यों को हुक कर सकते हैं।
आरोन ब्रेजर

6
मुझे नहीं लगता कि आपको उपवर्ग की अवधारणा मिलती है।
ऐस ग्रीन

5
अगर "बाद में स्टोरीबोर्ड में बेस क्लास कंट्रोलर के लिए उपवर्ग का प्रचार नहीं होता है", तो इसे "सबक्लास" नहीं कहा जाता है। यह कॉपी और पेस्ट है।
superarts.org

पहचान इंस्पेक्टर में चयनित अंतर्निहित वर्ग अभी भी एक उपवर्ग है। व्यावसायिक तर्क को आरंभ करने और नियंत्रित करने वाली वस्तु अभी भी एक उपवर्ग है। केवल इनकोडिंग दृश्य डेटा, स्टोरीबोर्ड फ़ाइल में XML के रूप में संग्रहीत करता है और इसके माध्यम से आरंभ किया जाता है initWithCoder:, जिसमें विरासत में मिला संबंध नहीं होता है। इस प्रकार का संबंध स्टोरीबोर्ड फ़ाइलों द्वारा समर्थित नहीं है।
आरोन ब्रेजर

4

Objc_setclass पद्धति चाइल्ड पीवीसी का उदाहरण नहीं बनाती है। लेकिन चाइल्ड पीवीसी से बाहर पॉपिंग करते समय चाइल्ड पीवीसी का डिनिट कॉल किया जा रहा है। चूंकि चाइल्ड पीवीसी, ऐप क्रैश के लिए कोई मेमोरी आवंटित नहीं की गई है। बेसकंट्रोलर के पास एक उदाहरण है, जबकि बच्चे वीसी के पास नहीं है।


2

यदि आप स्टोरीबोर्ड पर बहुत अधिक निर्भर नहीं हैं, तो आप नियंत्रक के लिए एक अलग .xib फ़ाइल बना सकते हैं।

मेन वीसी में उपयुक्त फ़ाइल के मालिक और आउटलेट्स को सेट करें MainViewControllerऔर init(nibName:bundle:)उसके बच्चों को ओवरराइड करें ताकि उसके बच्चे उसी निब और उसके आउटलेट तक पहुंच सकें।

आपका कोड इस तरह दिखना चाहिए:

class MainViewController: UIViewController {
    @IBOutlet weak var button: UIButton!

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: "MainViewController", bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        button.tintColor = .red
    }
}

और आपका चाइल्ड वीसी अपने माता-पिता के निब का फिर से उपयोग कर सकेगा:

class ChildViewController: MainViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        button.tintColor = .blue
    }
}

2

इधर-उधर से जवाब लेते हुए, मैं इस साफ समाधान के साथ आया।

इस फ़ंक्शन के साथ एक पैरेंट व्यू कंट्रोलर बनाएं।

class ParentViewController: UIViewController {


    func convert<T: ParentViewController>(to _: T.Type) {

        object_setClass(self, T.self)

    }

}

यह कंपाइलर को यह सुनिश्चित करने की अनुमति देता है कि चाइल्ड व्यू कंट्रोलर को पेरेंट व्यू कंट्रोलर से विरासत में मिले।

फिर जब भी आप एक सब क्लास का उपयोग करके इस कंट्रोलर से बहस करना चाहें तो आप कर सकते हैं:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    if let parentViewController = segue.destination as? ParentViewController {
        ParentViewController.convert(to: ChildViewController.self)
    }

}

शांत भाग यह है कि आप अपने आप में एक स्टोरीबोर्ड संदर्भ जोड़ सकते हैं, और फिर "अगला" चाइल्ड व्यू कंट्रोलर को कॉल कर सकते हैं।


1

संभवतः सबसे लचीला तरीका पुन: प्रयोज्य विचारों का उपयोग करना है।

(अलग XIB फ़ाइल में एक दृश्य बनाएं या Container viewस्टोरीबोर्ड में प्रत्येक उपवर्ग दृश्य नियंत्रक दृश्य में जोड़ें)


1
कृपया नीचे टिप्पणी करें। मुझे पता है कि मैं सीधे उस सवाल का जवाब नहीं देता लेकिन मैं जड़ समस्या के समाधान का प्रस्ताव देता हूं।
डेनस्किल

1

एक सरल, स्पष्ट, हर रोज समाधान है।

मौजूदा स्टोरीबोर्ड / कंट्रोलर को नए स्टोरीबार्ड / कंट्रोलर के अंदर रखें। एक कंटेनर दृश्य के रूप में IE।

यह "उपवर्ग" के लिए बिल्कुल अनुरूप अवधारणा है, इसके लिए, नियंत्रकों को देखें।

सब कुछ बिल्कुल एक उपवर्ग की तरह काम करता है।

जिस तरह आप आमतौर पर किसी अन्य दृश्य के अंदर एक दृश्य सबव्यू डालते हैं , स्वाभाविक रूप से आप आमतौर पर किसी अन्य दृश्य नियंत्रक के अंदर एक दृश्य नियंत्रक डालते हैं ।

आप इसे और कैसे कर सकते हैं?

यह आईओएस का एक मूल हिस्सा है, अवधारणा "सबव्यू" के रूप में सरल है।

यह आसान है ...

/*

Search screen is just a modification of our List screen.

*/

import UIKit

class Search: UIViewController {
    
    var list: List!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        list = (_sb("List") as! List
        addChild(list)
        view.addSubview(list.view)
        list.view.bindEdgesToSuperview()
        list.didMove(toParent: self)
    }
}

अब आपको स्पष्ट रूप से listवह करना होगा जो आप चाहते हैं

list.mode = .blah
list.tableview.reloadData()
list.heading = 'Search!'
list.searchBar.isHidden = false

आदि आदि।

कंटेनर के दृश्य "ठीक उसी तरह" उप-उपवाक्य हैं जिस तरह से "साक्षात्कार" "उप-वर्ग" की तरह हैं।

जाहिर है, आप "एक लेआउट को वश में नहीं कर सकते हैं" - इसका क्या मतलब होगा?

("सबक्लासिंग" का संबंध OO सॉफ्टवेयर से है और इसका "लेआउट" से कोई संबंध नहीं है।

स्पष्ट रूप से जब आप किसी दृश्य का पुन: उपयोग करना चाहते हैं, तो आप इसे किसी अन्य दृश्य के अंदर सबमिट कर देते हैं।

जब आप एक नियंत्रक लेआउट का फिर से उपयोग करना चाहते हैं, तो आप बस कंटेनर को किसी अन्य नियंत्रक के अंदर देखते हैं।

यह iOS के सबसे बुनियादी तंत्र की तरह है !!


नोट - वर्षों से यह कंटेनर दृश्य के रूप में गतिशील रूप से किसी अन्य दृश्य नियंत्रक को लोड करने के लिए तुच्छ है। अंतिम भाग में समझाया गया: https://stackoverflow.com/a/23403979/294884

नोट - "_sb" केवल एक स्पष्ट मैक्रो है जिसका उपयोग हम टाइपिंग को बचाने के लिए करते हैं,

func _sb(_ s: String)->UIViewController {
    // by convention, for a screen "SomeScreen.storyboard" the
    // storyboardID must be SomeScreenID
    return UIStoryboard(name: s, bundle: nil)
       .instantiateViewController(withIdentifier: s + "ID")
}

1

@ Jiiringí Zahálka के प्रेरक उत्तर के लिए धन्यवाद, मैंने 4 साल पहले अपने समाधान का जवाब यहां दिया था, लेकिन @Sayka ने मुझे उत्तर के रूप में पोस्ट करने का सुझाव दिया, इसलिए यहां यह है।

मेरी परियोजनाओं में, आम तौर पर, अगर मैं स्टोरीबोर्ड का उपयोग कर रहा हूं UIViewController उप-वर्ग के लिए, मैं हमेशा instantiate()स्टोरीबोर्ड से एक उदाहरण बनाने के लिए, उस उप-वर्ग में एक स्थिर विधि तैयार करता हूं । तो ओपी के प्रश्न को हल करने के लिए, यदि हम अलग-अलग उपवर्गों के लिए एक ही स्टोरीबोर्ड साझा करना चाहते हैं, तो हम setClass()इसे वापस करने से पहले बस उस उदाहरण के लिए कर सकते हैं ।

class func instantiate() -> SubClass {
    let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)!
    object_setClass(instance, SubClass.self)
    return (instance as? SubClass)!
}

0

जियो ज़ाल्का के जवाब से कोकोबो की टिप्पणी ने मुझे इस समाधान को प्राप्त करने में मदद की और इसने अच्छा काम किया।

func openChildA() {
    let storyboard = UIStoryboard(name: "Main", bundle: nil);
    let parentController = storyboard
        .instantiateViewController(withIdentifier: "ParentStoryboardID") 
        as! ParentClass;
    object_setClass(parentController, ChildA.self)
    self.present(parentController, animated: true, completion: nil);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.