Disons que j'ai un storyboard qui contient UINavigationController
comme contrôleur de vue initial. Son contrôleur de vue racine est une sous-classe de UITableViewController
, qui est BasicViewController
. Il a IBAction
qui est connecté au bouton de navigation droit de la barre de navigation
À partir de là, je voudrais utiliser le storyboard comme modèle pour d'autres vues sans avoir à créer des storyboards supplémentaires. Disons que ces vues auront exactement la même interface mais avec le contrôleur de vue racine de la classe SpecificViewController1
et SpecificViewController2
qui sont des sous-classes de BasicViewController
.
Ces 2 contrôleurs de vue auraient les mêmes fonctionnalités et interface à l'exception de la IBAction
méthode.
Ce serait comme ceci:
@interface BasicViewController : UITableViewController
@interface SpecificViewController1 : BasicViewController
@interface SpecificViewController2 : BasicViewController
Puis-je faire quelque chose comme ça?
Puis-je simplement instancier le storyboard de BasicViewController
mais avoir un contrôleur de vue racine dans la sous SpecificViewController1
- classe et SpecificViewController2
?
Merci.
Réponses:
excellente question - mais malheureusement seulement une réponse boiteuse. Je ne pense pas qu'il soit actuellement possible de faire ce que vous proposez car il n'y a pas d'initialiseurs dans UIStoryboard qui permettent de remplacer le contrôleur de vue associé au storyboard tel que défini dans les détails de l'objet dans le storyboard lors de l'initialisation. C'est lors de l'initialisation que tous les éléments de l'interface utilisateur du stoaryboard sont liés à leurs propriétés dans le contrôleur de vue.
Il s'initialise par défaut avec le contrôleur de vue spécifié dans la définition du storyboard.
Si vous essayez de réutiliser des éléments d'interface utilisateur que vous avez créés dans le storyboard, ils doivent toujours être liés ou associés à des propriétés dans lesquelles le contrôleur de vue les utilise pour qu'ils puissent "informer" le contrôleur de vue des événements.
Ce n'est pas un gros problème de copier sur une mise en page de storyboard, surtout si vous n'avez besoin que d'un design similaire pour 3 vues, mais si vous le faites, vous devez vous assurer que toutes les associations précédentes sont effacées, sinon il se bloquera quand il essaiera pour communiquer avec le contrôleur de vue précédent. Vous pourrez les reconnaître comme des messages d'erreur KVO dans la sortie du journal.
Quelques approches que vous pourriez adopter:
stockez les éléments de l'interface utilisateur dans un UIView - dans un fichier xib et instanciez-le à partir de votre classe de base et ajoutez-le en tant que sous-vue dans la vue principale, généralement self.view. Ensuite, vous utiliseriez simplement la disposition du storyboard avec des contrôleurs de vue essentiellement vides tenant leur place dans le storyboard mais avec la sous-classe de contrôleur de vue correcte qui leur est attribuée. Puisqu'ils hériteraient de la base, ils auraient ce point de vue.
créez la mise en page dans le code et installez-la à partir de votre contrôleur de vue de base. De toute évidence, cette approche va à l'encontre de l'objectif de l'utilisation du storyboard, mais peut être la voie à suivre dans votre cas. Si vous avez d'autres parties de l'application qui bénéficieraient de l'approche storyboard, vous pouvez dévier ici et là si nécessaire. Dans ce cas, comme ci-dessus, vous utiliseriez simplement des contrôleurs de vue bancaire avec votre sous-classe attribuée et laissez le contrôleur de vue de base installer l'interface utilisateur.
Ce serait bien si Apple proposait un moyen de faire ce que vous proposez, mais le problème d'avoir les éléments graphiques pré-liés à la sous-classe du contrôleur serait toujours un problème.
Excellente nouvelle année!! être bien
la source
Le code de la ligne que nous recherchons est:
Dans Storyboard -> ajoutez UIViewController, donnez-lui un nom de classe ParentVC.
la source
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
ne change pas. Ainsi, l'inspection de l'objet (par exemple la lecture des valeurs de _ivar / propriété) aprèsobject_setClass
peut provoquer des plantages.Comme l'indique la réponse acceptée, il ne semble pas possible de faire avec des storyboards.
Ma solution est d'utiliser Nib's - tout comme les développeurs les utilisaient avant les storyboards. Si vous voulez avoir un contrôleur de vue réutilisable et sous-classable (ou même une vue), ma recommandation est d'utiliser Nibs.
Lorsque vous connectez tous vos points de vente au "File Owner" dans le,
MyViewController.xib
vous ne spécifiez PAS la classe sous laquelle le Nib doit être chargé, vous spécifiez simplement des paires clé-valeur: " cette vue doit être connectée à ce nom de variable d'instance ." Lors de l'appel,[SubclassMyViewController alloc] initWithNibName:
le processus d'initialisation spécifie quel contrôleur de vue sera utilisé pour " contrôler " la vue que vous avez créée dans la pointe.la source
Il est possible qu'un storyboard instancie différentes sous-classes d'un contrôleur de vue personnalisé, bien que cela implique une technique légèrement peu orthodoxe: remplacer la
alloc
méthode pour le contrôleur de vue. Lorsque le contrôleur de vue personnalisé est créé, la méthode d'allocation remplacée renvoie en fait le résultat de l'exécutionalloc
sur la sous-classe.Je devrais commencer la réponse à condition que, bien que je l'ai testé dans divers scénarios et que je n'ai reçu aucune erreur, je ne peux pas garantir qu'il fera face à des configurations plus complexes (mais je ne vois aucune raison pour laquelle cela ne devrait pas fonctionner) . De plus, je n'ai soumis aucune application à l'aide de cette méthode, il y a donc une chance extérieure qu'elle soit rejetée par le processus de révision d'Apple (bien qu'une fois de plus je ne vois aucune raison pour laquelle cela devrait).
À des fins de démonstration, j'ai une sous-classe de
UIViewController
calledTestViewController
, qui a un IBOutlet UILabel et un IBAction. Dans mon storyboard, j'ai ajouté un contrôleur de vue et modifié sa classe enTestViewController
, et connecté l'IBOutlet à un UILabel et l'IBAction à un UIButton. Je présente le TestViewController au moyen d'un segment modal déclenché par un UIButton sur le viewController précédent.Pour contrôler quelle classe est instanciée, j'ai ajouté une variable statique et des méthodes de classe associées afin d'obtenir / définir la sous-classe à utiliser (je suppose que l'on pourrait adopter d'autres façons de déterminer quelle sous-classe doit être instanciée):
TestViewController.m:
Pour mon test, j'ai deux sous-classes de
TestViewController
:RedTestViewController
etGreenTestViewController
. Les sous-classes ont chacune des propriétés supplémentaires et chaque remplacementviewDidLoad
pour changer la couleur d'arrière-plan de la vue et mettre à jour le texte de l'IBOutlet UILabel:RedTestViewController.m:
GreenTestViewController.m:
À certaines occasions, je pourrais vouloir s'instancier
TestViewController
, à d'autres occasionsRedTestViewController
ouGreenTestViewController
. Dans le contrôleur de vue précédent, je le fais au hasard comme suit:Notez que la
setClassForStoryBoard
méthode vérifie que le nom de classe demandé est bien une sous-classe de TestViewController, pour éviter toute confusion. La référence ci-dessusBlueTestViewController
est là pour tester cette fonctionnalité.la source
essayez ceci, après instantiateViewControllerWithIdentifier.
comme :
la source
EXC_BAD_ACCESS
, donc ne le recommande pas.init
ne sera pas appelé non plus. De telles contraintes rendent toute approche inutilisable.En me basant en particulier sur les réponses de nickgzzjr et Jiří Zahálka, ainsi que sur le commentaire sous le second de CocoaBob, j'ai préparé une courte méthode générique faisant exactement ce dont OP a besoin. Il vous suffit de vérifier le nom du storyboard et l'ID du storyboard de View Controller
Des options sont ajoutées pour éviter de forcer le dépliage (avertissements swiftlint), mais la méthode renvoie les objets corrects.
la source
Bien que ce ne soit pas strictement une sous-classe, vous pouvez:
Voici un exemple d'un tutoriel Bloc que j'ai écrit, en sous-classant
ViewController
avecWhiskeyViewController
:Cela vous permet de créer des sous-classes de sous-classes de contrôleur de vue dans le storyboard. Vous pouvez ensuite utiliser
instantiateViewControllerWithIdentifier:
pour créer des sous-classes spécifiques.Cette approche est un peu inflexible: les modifications ultérieures dans le storyboard vers le contrôleur de classe de base ne se propagent pas à la sous-classe. Si vous avez beaucoup de sous-classes, vous serez peut-être mieux avec l'une des autres solutions, mais cela suffira à la rigueur.
la source
initWithCoder:
, n'ont pas de relation héritée. Ce type de relation n'est pas pris en charge par les fichiers de storyboard.La méthode Objc_setclass ne crée pas d'instance de childvc. Mais tout en sortant de childvc, la deinit de childvc est appelée. Puisqu'il n'y a pas de mémoire allouée séparément pour childvc, l'application se bloque. Basecontroller a une instance, alors que l'enfant vc n'en a pas.
la source
Si vous n'êtes pas trop dépendant des storyboards, vous pouvez créer un fichier .xib distinct pour le contrôleur.
Définissez le propriétaire et les prises du fichier appropriés
MainViewController
sur etinit(nibName:bundle:)
dans le VC principal afin que ses enfants puissent accéder au même Nib et à ses prises.Votre code doit ressembler à ceci:
Et votre VC enfant pourra réutiliser la pointe de son parent:
la source
En prenant des réponses d'ici et là, j'ai trouvé cette solution intéressante.
Créez un contrôleur de vue parent avec cette fonction.
Cela permet au compilateur de s'assurer que le contrôleur de vue enfant hérite du contrôleur de vue parent.
Ensuite, chaque fois que vous souhaitez passer à ce contrôleur en utilisant une sous-classe, vous pouvez faire:
La partie intéressante est que vous pouvez ajouter une référence de storyboard à lui-même, puis continuer à appeler le contrôleur de vue enfant "suivant".
la source
Le moyen le plus flexible est probablement d'utiliser des vues réutilisables.
(Créez une vue dans un fichier XIB séparé ou
Container view
ajoutez-la à chaque scène de contrôleur de vue de sous-classe dans le storyboard)la source
Il existe une solution simple, évidente et quotidienne.
Mettez simplement le storyboard / contrôleur existant dans le nouveau storyobard / contrôleur. IE en tant que vue de conteneur.
C'est le concept exactement analogue au "sous-classement", pour les contrôleurs de vue.
Tout fonctionne exactement comme dans une sous-classe.
Tout comme vous mettez généralement une sous-vue de vue dans une autre vue , vous placez naturellement généralement un contrôleur de vue dans un autre contrôleur de vue .
Comment pouvez-vous le faire autrement?
C'est une partie de base d'iOS, aussi simple que le concept de «sous-vue».
C'est aussi simple que ça ...
Tu dois évidemment faire
list
ce que tu veux avecetc.
Les vues de conteneur sont "juste comme" les sous-classes de la même manière que les "sous-vues" sont "juste comme" les sous-classes.
Bien sûr, vous ne pouvez pas "sous-classer une mise en page" - qu'est-ce que cela signifierait?
("Sous-classement" concerne le logiciel OO et n'a aucun lien avec les "mises en page".)
Évidemment, lorsque vous souhaitez réutiliser une vue, vous la sous-visualisez simplement dans une autre vue.
Lorsque vous souhaitez réutiliser une disposition de contrôleur, il vous suffit de l'afficher dans un autre contrôleur.
C'est comme le mécanisme le plus basique d'iOS !!
Remarque - depuis des années, il est devenu trivial de charger dynamiquement un autre contrôleur de vue en tant que vue de conteneur. Expliqué dans la dernière section: https://stackoverflow.com/a/23403979/294884
Remarque - "_sb" est juste une macro évidente que nous utilisons pour enregistrer la saisie,
la source
Merci pour la réponse inspirante de @ Jiří Zahálka, j'ai répondu à ma solution il y a 4 ans ici , mais @Sayka m'a suggéré de l'afficher comme réponse, alors la voici.
Dans mes projets, normalement, si j'utilise Storyboard pour une sous-classe UIViewController, je prépare toujours une méthode statique appelée
instantiate()
dans cette sous-classe, pour créer facilement une instance à partir de Storyboard. Donc, pour résoudre la question de OP, si nous voulons partager le même Storyboard pour différentes sous-classes, nous pouvons simplement accédersetClass()
à cette instance avant de la renvoyer.la source
Le commentaire de Cocoabob de la réponse de Jiří Zahálka m'a aidé à obtenir cette solution et cela a bien fonctionné.
la source