Angenommen, ich habe ein Storyboard, das UINavigationController
als Controller für die Erstansicht enthält . Seine Wurzel - View - Controller ist Unterklasse von UITableViewController
, das ist BasicViewController
. Es hat, IBAction
was 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 SpecificViewController1
und SpecificViewController2
die Unterklassen sind BasicViewController
.
Diese beiden Ansichtscontroller hätten mit Ausnahme der IBAction
Methode 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 SpecificViewController1
und SpecificViewController2
?
Vielen Dank.
Antworten:
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
quelle
Der gesuchte Zeilencode lautet:
Geben Sie in Storyboard -> UIViewController hinzufügen einen ParentVC-Klassennamen an.
quelle
class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
self
nicht ändert. Eine Inspektion des Objekts (z. B. Lesen von _ivar / property-Werten) nachobject_setClass
kann daher zu Abstürzen führen.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.
Wenn Sie alle Ihre Steckdosen mit dem "Dateibesitzer" verbinden, in dem
MyViewController.xib
Sie 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.quelle
Es ist möglich, dass ein Storyboard verschiedene Unterklassen eines benutzerdefinierten Ansichts-Controllers instanziiert, obwohl dies eine etwas unorthodoxe Technik beinhaltet: Überschreiben der
alloc
Methode für den Ansichts-Controller. Wenn der benutzerdefinierte Ansichtscontroller erstellt wird, gibt die überschriebene Zuweisungsmethode tatsächlich das Ergebnis der Ausführungalloc
in 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
UIViewController
aufgerufenTestViewController
, die ein UILabel IBOutlet und eine IBAction hat. In meinem Storyboard habe ich einen View Controller hinzugefügt und seine Klasse geändertTestViewController
und 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.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:
Für meinen Test habe ich zwei Unterklassen von
TestViewController
:RedTestViewController
undGreenTestViewController
. Die Unterklassen verfügen jeweils über zusätzliche Eigenschaften und werden überschriebenviewDidLoad
, um die Hintergrundfarbe der Ansicht zu ändern und den Text des UILabel IBOutlet zu aktualisieren:RedTestViewController.m:
GreenTestViewController.m:
In einigen Fällen möchte ich mich vielleicht
TestViewController
selbst instanziieren , in anderen FällenRedTestViewController
oderGreenTestViewController
. In der vorhergehenden Ansichtssteuerung mache ich dies zufällig wie folgt:Beachten Sie, dass die
setClassForStoryBoard
Methode überprüft, ob der angeforderte Klassenname tatsächlich eine Unterklasse von TestViewController ist, um Verwechslungen zu vermeiden. Der obige Verweis aufBlueTestViewController
dient zum Testen dieser Funktionalität.quelle
Versuchen Sie dies nach instantiateViewControllerWithIdentifier.
mögen :
quelle
EXC_BAD_ACCESS
, also empfehle ich dies nicht.init
auch nicht gerufen. Solche Einschränkungen machen alle Ansätze unbrauchbar.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
Optionen werden hinzugefügt, um ein erzwungenes Auspacken zu vermeiden (Swiftlint-Warnungen), aber die Methode gibt korrekte Objekte zurück.
quelle
Obwohl es sich nicht ausschließlich um eine Unterklasse handelt, können Sie:
Hier ein Beispiel aus einem Block Tutorial Ich schrieb, Subklassen
ViewController
mitWhiskeyViewController
: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.
quelle
initWithCoder:
, haben keine vererbte Beziehung. Diese Art von Beziehung wird von Storyboard-Dateien nicht unterstützt.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.
quelle
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
MainViewController
und überschreiben Sie sieinit(nibName:bundle:)
im Haupt-VC, damit die untergeordneten Dateien auf dieselbe Feder und die Steckdosen zugreifen können.Ihr Code sollte folgendermaßen aussehen:
Und Ihr Kind VC kann die Feder seiner Eltern wiederverwenden:
quelle
Ich nahm die Antworten von hier und da entgegen und fand diese saubere Lösung.
Erstellen Sie mit dieser Funktion einen übergeordneten Ansichtscontroller.
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:
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.
quelle
Am flexibelsten ist es wahrscheinlich, wiederverwendbare Ansichten zu verwenden.
(Erstellen Sie eine Ansicht in einer separaten XIB-Datei oder
Container view
fügen Sie sie jeder View-Controller-Szene der Unterklasse im Storyboard hinzu.)quelle
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 ...
Sie müssen jetzt offensichtlich
list
tun, was Sie wollenetc 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.
quelle
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, einfachsetClass()
zu dieser Instanz wechseln, bevor wir es zurückgeben.quelle
Cocoabobs Kommentar aus der Antwort von Jiří Zahálka hat mir geholfen, diese Lösung zu finden, und sie hat gut funktioniert.
quelle