Verwendung eines einzelnen Storyboards uiviewcontroller für mehrere Unterklassen

118

Angenommen, ich habe ein Storyboard, das UINavigationControllerals Controller für die Erstansicht enthält . Seine Wurzel - View - Controller ist Unterklasse von UITableViewController, das ist BasicViewController. Es hat, IBActionwas mit der rechten Navigationsschaltfläche der Navigationsleiste verbunden ist.

Von dort möchte ich das Storyboard als Vorlage für andere Ansichten verwenden, ohne zusätzliche Storyboards erstellen zu müssen. Sagen Sie diese Ansichten genau die gleiche Schnittstelle haben, aber mit Root - View - Controller der Klasse SpecificViewController1und SpecificViewController2die Unterklassen sind BasicViewController.
Diese beiden Ansichtscontroller hätten mit Ausnahme der IBActionMethode dieselbe Funktionalität und Schnittstelle .
Es wäre wie folgt:

@interface BasicViewController : UITableViewController

@interface SpecificViewController1 : BasicViewController

@interface SpecificViewController2 : BasicViewController

Kann ich so etwas machen?
Kann ich das Storyboard von nur instanziieren BasicViewController, habe aber einen Root View Controller für die Unterklasse SpecificViewController1und SpecificViewController2?

Vielen Dank.

verdy
quelle
3
Es könnte erwähnenswert sein, dass Sie dies mit Feder tun können. Aber wenn Sie wie ich sind und einige nette Funktionen wünschen, die nur das Storyboard hat (z. B. statische / Prototyp-Zelle), dann haben wir wahrscheinlich kein Glück.
Joseph Lin

Antworten:

57

tolle Frage - aber leider nur eine lahme Antwort. Ich glaube nicht, dass es derzeit möglich ist, das zu tun, was Sie vorschlagen, da es in UIStoryboard keine Initialisierer gibt, mit denen der mit dem Storyboard verknüpfte Ansichtscontroller überschrieben werden kann, wie in den Objektdetails im Storyboard bei der Initialisierung definiert. Bei der Initialisierung werden alle UI-Elemente im Stoaryboard mit ihren Eigenschaften im View Controller verknüpft.

Die Initialisierung erfolgt standardmäßig mit dem in der Storyboard-Definition angegebenen Ansichts-Controller.

Wenn Sie versuchen, die im Storyboard erstellten UI-Elemente wiederzuverwenden, müssen sie dennoch mit Eigenschaften verknüpft oder verknüpft werden, in denen der View Controller sie verwendet, damit sie den View Controller über Ereignisse "informieren" können.

Es ist keine große Sache, über ein Storyboard-Layout zu kopieren, insbesondere wenn Sie nur ein ähnliches Design für 3 Ansichten benötigen. Wenn Sie dies jedoch tun, müssen Sie sicherstellen, dass alle vorherigen Zuordnungen gelöscht werden, da es sonst zu Abstürzen kommt, wenn es versucht wird um mit dem vorherigen View Controller zu kommunizieren. Sie können sie als KVO-Fehlermeldungen in der Protokollausgabe erkennen.

Ein paar Ansätze, die Sie wählen könnten:

  • Speichern Sie die UI-Elemente in einer UIView - in einer xib-Datei, instanziieren Sie sie aus Ihrer Basisklasse und fügen Sie sie als Unteransicht in der Hauptansicht hinzu, normalerweise self.view. Dann würden Sie einfach das Storyboard-Layout verwenden, wobei im Grunde leere Ansichts-Controller ihren Platz im Storyboard behalten, ihnen jedoch die richtige Ansichts-Controller-Unterklasse zugewiesen ist. Da sie von der Basis erben würden, würden sie diese Ansicht erhalten.

  • Erstellen Sie das Layout im Code und installieren Sie es von Ihrem Basisansichts-Controller. Offensichtlich macht dieser Ansatz den Zweck der Verwendung des Storyboards zunichte, kann aber in Ihrem Fall der richtige Weg sein. Wenn Sie andere Teile der App haben, die vom Storyboard-Ansatz profitieren würden, können Sie gegebenenfalls hier und da davon abweichen. In diesem Fall würden Sie wie oben nur Bank View Controller mit Ihrer zugewiesenen Unterklasse verwenden und den Base View Controller die Benutzeroberfläche installieren lassen.

Es wäre schön, wenn Apple einen Weg finden würde, um das zu tun, was Sie vorschlagen, aber das Problem, dass die grafischen Elemente mit der Controller-Unterklasse vorverknüpft sind, wäre immer noch ein Problem.

Ich wünsche dir ein tolles neues Jahr !! gut sein

CocoaEv
quelle
Das war schnell. Wie ich dachte, wäre es nicht möglich. Derzeit habe ich eine Lösung gefunden, indem ich nur diese BasicViewController-Klasse habe und zusätzliche Eigenschaften habe, um anzugeben, als welche "Klasse" / "Modus" sie fungieren wird. Danke trotzdem.
verdy
2
Schade :( Ich denke, ich muss den gleichen View-Controller kopieren und einfügen und seine Klasse als Workaround ändern.
Hlung
1
Und deshalb mag ich Storyboards nicht ... irgendwie funktionieren sie nicht wirklich, wenn Sie ein bisschen mehr als Standardansichten machen ...
TheEye
So traurig, als du das gehört hast. Ich suche nach einer Lösung
Tony
2
Es gibt einen anderen Ansatz: Geben Sie die benutzerdefinierte Logik in verschiedenen Delegaten an und weisen Sie in prepareForSegue den richtigen Delegaten zu. Auf diese Weise erstellen Sie 1 UIViewController + 1 UIViewController im Storyboard, haben jedoch mehrere Implementierungsversionen.
plam4u
45

Der gesuchte Zeilencode lautet:

object_setClass(AnyObject!, AnyClass!)

Geben Sie in Storyboard -> UIViewController hinzufügen einen ParentVC-Klassennamen an.

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
    }
}
Jiří Zahálka
quelle
5
Danke, es funktioniert einfach zum Beispiel:class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
CocoaBob
3
Ich bin mir nicht sicher, ob ich verstehe, wie das funktionieren soll. Der Elternteil setzt seine Klasse als die eines Kindes? Wie können Sie dann mehrere Kinder haben?!
user1366265
2
Sie, mein Herr, haben meinen Tag gemacht
16:38 Uhr
2
OK Leute, lassen Sie mich das etwas genauer erklären: Was wollen wir erreichen? Wir möchten unseren ParentViewController in Unterklassen unterteilen, damit wir sein Storyboard für weitere Klassen verwenden können. Die magische Linie, die alles macht, ist in meiner Lösung hervorgehoben und muss in awakeFromNib in ParentVC verwendet werden. Was dann passiert, ist, dass es alle Methoden von neu gesetztem ChildVC1 verwendet, das als Unterklasse wird. Wenn Sie es für mehr ChildVCs verwenden möchten? Machen Sie einfach Ihre Logik in awakeFromNib .. if (type = a) {object_setClass (self, ChildVC1.self)} else {object_setClass (self.ChildVC2.self)} Viel Glück.
Jiří Zahálka
10
Seien Sie sehr vorsichtig, wenn Sie dies verwenden! Normalerweise sollte dies überhaupt nicht verwendet werden ... Dies ändert einfach den isa-Zeiger des angegebenen Zeigers und ordnet den Speicher nicht neu zu, um z. B. unterschiedliche Eigenschaften zu berücksichtigen. Ein Indikator dafür ist, dass sich der Zeiger auf selfnicht ändert. Eine Inspektion des Objekts (z. B. Lesen von _ivar / property-Werten) nach object_setClasskann daher zu Abstürzen führen.
Patrik
15

Wie in der akzeptierten Antwort angegeben, sieht es nicht so aus, als ob es mit Storyboards möglich wäre.

Meine Lösung besteht darin, Nibs zu verwenden - genau wie Entwickler sie vor Storyboards verwendet haben. Wenn Sie einen wiederverwendbaren, unterklassierbaren Ansichts-Controller (oder sogar eine Ansicht) haben möchten, empfehle ich die Verwendung von Schreibfedern.

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

Wenn Sie alle Ihre Steckdosen mit dem "Dateibesitzer" verbinden, in dem MyViewController.xibSie NICHT angeben, als welche Klasse die Schreibfeder geladen werden soll, geben Sie lediglich Schlüssel-Wert-Paare an: " Diese Ansicht sollte mit dem Namen dieser Instanzvariablen verbunden sein ." Beim Aufrufen [SubclassMyViewController alloc] initWithNibName:des Initialisierungsprozesses wird angegeben, mit welchem ​​Ansichtscontroller die in der Schreibfeder erstellte Ansicht " gesteuert " wird.

kgaidis
quelle
Überraschenderweise scheint dies dank der ObjC-Laufzeitbibliothek mit Storyboards möglich zu sein. Überprüfen Sie meine Antwort hier: stackoverflow.com/a/57622836/7183675
Adam Tucholski
9

Es ist möglich, dass ein Storyboard verschiedene Unterklassen eines benutzerdefinierten Ansichts-Controllers instanziiert, obwohl dies eine etwas unorthodoxe Technik beinhaltet: Überschreiben der allocMethode für den Ansichts-Controller. Wenn der benutzerdefinierte Ansichtscontroller erstellt wird, gibt die überschriebene Zuweisungsmethode tatsächlich das Ergebnis der Ausführung allocin der Unterklasse zurück.

Ich sollte der Antwort den Vorbehalt voranstellen, dass ich, obwohl ich sie in verschiedenen Szenarien getestet und keine Fehler erhalten habe, nicht sicherstellen kann, dass sie mit komplexeren Einstellungen fertig wird (aber ich sehe keinen Grund, warum sie nicht funktionieren sollte). . Außerdem habe ich keine Apps mit dieser Methode eingereicht, sodass die Möglichkeit besteht, dass sie vom Überprüfungsprozess von Apple abgelehnt werden (auch hier sehe ich keinen Grund, warum dies der Fall sein sollte).

Zu Demonstrationszwecken habe ich eine Unterklasse von UIViewControlleraufgerufen TestViewController, die ein UILabel IBOutlet und eine IBAction hat. In meinem Storyboard habe ich einen View Controller hinzugefügt und seine Klasse geändert TestViewControllerund das IBOutlet mit einem UILabel und die IBAction mit einem UIButton verbunden. Ich präsentiere den TestViewController über einen modalen Übergang, der durch einen UIButton auf dem vorhergehenden viewController ausgelöst wird.

Storyboard-Bild

Um zu steuern, welche Klasse instanziiert wird, habe ich eine statische Variable und zugehörige Klassenmethoden hinzugefügt, um die zu verwendende Unterklasse abzurufen / festzulegen (ich denke, man könnte andere Methoden anwenden, um zu bestimmen, welche Unterklasse instanziiert werden soll):

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];
        }
    }
}

Für meinen Test habe ich zwei Unterklassen von TestViewController: RedTestViewControllerund GreenTestViewController. Die Unterklassen verfügen jeweils über zusätzliche Eigenschaften und werden überschrieben viewDidLoad, um die Hintergrundfarbe der Ansicht zu ändern und den Text des UILabel IBOutlet zu aktualisieren:

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";
}

In einigen Fällen möchte ich mich vielleicht TestViewControllerselbst instanziieren , in anderen Fällen RedTestViewControlleroder GreenTestViewController. In der vorhergehenden Ansichtssteuerung mache ich dies zufällig wie folgt:

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"];
}

Beachten Sie, dass die setClassForStoryBoardMethode überprüft, ob der angeforderte Klassenname tatsächlich eine Unterklasse von TestViewController ist, um Verwechslungen zu vermeiden. Der obige Verweis auf BlueTestViewControllerdient zum Testen dieser Funktionalität.

pbasdf
quelle
Wir haben im Projekt etwas Ähnliches getan, aber die Zuweisungsmethode des UIViewController überschrieben, um eine Unterklasse von einer externen Klasse abzurufen, die die vollständigen Informationen zu allen Überschreibungen sammelt. Funktioniert perfekt.
Tim
Übrigens funktioniert diese Methode möglicherweise nicht mehr so ​​schnell, wie Apple aufhört, Alloc on View Controller aufzurufen. Für das Beispiel erhält die NSManagedObject-Klasse niemals eine Zuweisungsmethode. Ich denke, Apple könnte den Code auf eine andere Methode kopieren: vielleicht + allocManagedObject
Tim
7

Versuchen Sie dies nach instantiateViewControllerWithIdentifier.

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

mögen :

SubViewController *vc = [sb instantiateViewControllerWithIdentifier:@"MainViewController"];
[vc setClass:[SubViewController class]];
莫 振华
quelle
Bitte fügen Sie einige hilfreiche Erklärungen zu den Funktionen Ihres Codes hinzu.
Codeforester
7
Was passiert damit, wenn Sie Instanzvariablen aus der Unterklasse verwenden? Ich vermute einen Absturz, weil nicht genügend Speicher dafür vorhanden ist. In meinen Tests habe ich bekommen EXC_BAD_ACCESS, also empfehle ich dies nicht.
Legoless
1
Dies funktioniert nicht, wenn Sie neue Variablen in der untergeordneten Klasse hinzufügen. Und Kinder werden initauch nicht gerufen. Solche Einschränkungen machen alle Ansätze unbrauchbar.
Al Zonke
6

Gestützt vor allem auf nickgzzjr und Jiří Zahálka Antworten sowie Kommentar unter dem zweiten von CocoaBob ive vorbereitete kurz generische Methode zu tun genau das, was OP Bedürfnisse. Sie müssen nur den Storyboard-Namen und die View Controller-Storyboard-ID überprüfen

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
    }

Optionen werden hinzugefügt, um ein erzwungenes Auspacken zu vermeiden (Swiftlint-Warnungen), aber die Methode gibt korrekte Objekte zurück.

Adam Tucholski
quelle
5

Obwohl es sich nicht ausschließlich um eine Unterklasse handelt, können Sie:

  1. option-Ziehen Sie den Controller für die Basisklassenansicht in der Dokumentübersicht, um eine Kopie zu erstellen
  2. Verschieben Sie die neue View Controller-Kopie an eine separate Stelle im Storyboard
  3. Ändern Sie die Klasse im Identity Inspector in den Controller für die Unterklassenansicht

Hier ein Beispiel aus einem Block Tutorial Ich schrieb, Subklassen ViewControllermit WhiskeyViewController:

Animation der obigen drei Schritte

Auf diese Weise können Sie im Storyboard Unterklassen von View Controller-Unterklassen erstellen. Sie können dann instantiateViewControllerWithIdentifier:bestimmte Unterklassen erstellen.

Dieser Ansatz ist etwas unflexibel: Spätere Änderungen innerhalb des Storyboards am Basisklassen-Controller werden nicht an die Unterklasse weitergegeben. Wenn Sie viele Unterklassen haben, sind Sie mit einer der anderen Lösungen möglicherweise besser dran, aber das reicht zur Not.

Aaron Brager
quelle
11
Dies ist kein Unterklassenkamerad, sondern nur das Duplizieren eines ViewControllers.
Ace Green
1
Das ist nicht richtig. Es wird zu einer Unterklasse, wenn Sie die Klasse in die Unterklasse ändern (Schritt 3). Anschließend können Sie die gewünschten Änderungen vornehmen und sich mit den Ausgängen / Aktionen in Ihrer Unterklasse verbinden.
Aaron Brager
6
Ich glaube nicht, dass Sie das Konzept der Unterklasse verstehen.
Ace Green
5
Wenn "spätere Änderungen innerhalb des Storyboards am Basisklassen-Controller nicht in die Unterklasse übertragen werden", wird dies nicht als "Unterklasse" bezeichnet. Es ist Kopieren und Einfügen.
Superarts.org
Die zugrunde liegende Klasse, die im Identitätsinspektor ausgewählt wurde, ist weiterhin eine Unterklasse. Das Objekt, das initialisiert wird und die Geschäftslogik steuert, ist immer noch eine Unterklasse. Nur die codierten Ansichtsdaten, die als XML in der Storyboard-Datei gespeichert und über initialisiert wurden initWithCoder:, haben keine vererbte Beziehung. Diese Art von Beziehung wird von Storyboard-Dateien nicht unterstützt.
Aaron Brager
4

Die Methode Objc_setclass erstellt keine Instanz von childvc. Aber während Sie aus childvc herausspringen, wird deinit von childvc aufgerufen. Da für childvc kein Speicher separat zugewiesen ist, stürzt die App ab. Basecontroller hat eine Instanz, Child vc nicht.

user8044830
quelle
2

Wenn Sie nicht zu sehr auf Storyboards angewiesen sind, können Sie eine separate .xib-Datei für den Controller erstellen.

Stellen Sie den Besitzer und die Steckdosen der entsprechenden Datei auf MainViewControllerund überschreiben Sie sie init(nibName:bundle:)im Haupt-VC, damit die untergeordneten Dateien auf dieselbe Feder und die Steckdosen zugreifen können.

Ihr Code sollte folgendermaßen aussehen:

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
    }
}

Und Ihr Kind VC kann die Feder seiner Eltern wiederverwenden:

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

Ich nahm die Antworten von hier und da entgegen und fand diese saubere Lösung.

Erstellen Sie mit dieser Funktion einen übergeordneten Ansichtscontroller.

class ParentViewController: UIViewController {


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

        object_setClass(self, T.self)

    }

}

Auf diese Weise kann der Compiler sicherstellen, dass der untergeordnete Ansichtscontroller vom übergeordneten Ansichtscontroller erbt.

Wann immer Sie dann mit einer Unterklasse zu diesem Controller wechseln möchten, können Sie Folgendes tun:

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)
    }

}

Der coole Teil ist, dass Sie einen Storyboard-Verweis zu sich selbst hinzufügen und dann den "nächsten" untergeordneten Ansichts-Controller aufrufen können.

nickgzzjr
quelle
1

Am flexibelsten ist es wahrscheinlich, wiederverwendbare Ansichten zu verwenden.

(Erstellen Sie eine Ansicht in einer separaten XIB-Datei oder Container viewfügen Sie sie jeder View-Controller-Szene der Unterklasse im Storyboard hinzu.)

DanSkeel
quelle
1
Bitte kommentieren Sie, wenn Sie abstimmen. Ich weiß, dass ich diese Frage nicht direkt beantworte, aber ich schlage eine Lösung für das Grundproblem vor.
DanSkeel
1

Es gibt eine einfache, offensichtliche und alltägliche Lösung.

Legen Sie einfach das vorhandene Storyboard / Controller in den neuen Storyobard / Controller. IE als Containeransicht.

Dies ist das genau analoge Konzept zur "Unterklasse" für Ansichtssteuerungen.

Alles funktioniert genau wie in einer Unterklasse.

So wie Sie normalerweise eine Ansichtsunteransicht in eine andere Ansicht einfügen, fügen Sie normalerweise einen Ansichtscontroller in einen anderen Ansichtscontroller ein .

Wie sonst könnten Sie es tun?

Es ist ein grundlegender Teil von iOS, so einfach wie das Konzept "Unteransicht".

So einfach ist das ...

/*

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)
    }
}

Sie müssen jetzt offensichtlich listtun, was Sie wollen

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

etc etc. etc.

Containeransichten sind "genau wie" Unterklassen, genauso wie "Unteransichten" "genau wie" Unterklassen sind.

Natürlich können Sie ein Layout nicht "unterordnen" - was würde das überhaupt bedeuten?

("Unterklassen" beziehen sich auf OO-Software und haben keine Verbindung zu "Layouts".)

Wenn Sie eine Ansicht wiederverwenden möchten, müssen Sie sie natürlich nur in einer anderen Ansicht anzeigen.

Wenn Sie ein Controller-Layout wiederverwenden möchten, sehen Sie es einfach in einem anderen Controller.

Dies ist wie der grundlegendste Mechanismus von iOS!


Hinweis - Seit Jahren ist es trivial, einen anderen Ansichtscontroller dynamisch als Containeransicht zu laden. Im letzten Abschnitt erklärt: https://stackoverflow.com/a/23403979/294884

Hinweis - "_sb" ist nur ein offensichtliches Makro, das wir zum Speichern der Eingabe verwenden.

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")
}
Fattie
quelle
1

Vielen Dank für die inspirierende Antwort von @ Jiří Zahálka. Ich habe meine Lösung vor 4 Jahren hier beantwortet, aber @Sayka hat mir vorgeschlagen, sie als Antwort zu veröffentlichen, also hier ist sie.

Wenn ich in meinen Projekten Storyboard für eine UIViewController-Unterklasse verwende, bereite ich normalerweise immer eine statische Methode vor, die instantiate()in dieser Unterklasse aufgerufen wird, um auf einfache Weise eine Instanz aus Storyboard zu erstellen. Um die Frage von OP zu lösen, können wir, wenn wir dasselbe Storyboard für verschiedene Unterklassen freigeben möchten, einfach setClass()zu dieser Instanz wechseln, bevor wir es zurückgeben.

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

Cocoabobs Kommentar aus der Antwort von Jiří Zahálka hat mir geholfen, diese Lösung zu finden, und sie hat gut funktioniert.

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);
}
Sayka
quelle