Existe-t-il un moyen intégré pour passer de a UIView
à son UIViewController
? Je sais que vous pouvez passer de UIViewController
à son UIView
via [self view]
mais je me demandais s'il y avait une référence inverse?
la source
Existe-t-il un moyen intégré pour passer de a UIView
à son UIViewController
? Je sais que vous pouvez passer de UIViewController
à son UIView
via [self view]
mais je me demandais s'il y avait une référence inverse?
Puisque c'est la réponse acceptée depuis longtemps, je sens que je dois la rectifier avec une meilleure réponse.
Quelques commentaires sur le besoin:
Voici un exemple de mise en œuvre:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
La vue s'interface avec son délégué (comme UITableView
fait, par exemple) et peu importe si elle est implémentée dans le contrôleur de vue ou dans toute autre classe que vous finissez par utiliser.
Ma réponse originale suit: Je ne recommande pas cela, ni le reste des réponses où un accès direct au contrôleur de vue est obtenu
Il n'y a pas de moyen intégré de le faire. Bien que vous puissiez le contourner en ajoutant un IBOutlet
sur UIView
et en les connectant dans Interface Builder, cela n'est pas recommandé. La vue ne doit pas connaître le contrôleur de vue. Au lieu de cela, vous devez faire comme @Phil M le suggère et créer un protocole à utiliser en tant que délégué.
En utilisant l'exemple posté par Brock, je l'ai modifié pour qu'il s'agisse d'une catégorie de UIView à la place de UIViewController et l'ai rendu récursif afin que toute sous-vue puisse (espérons-le) trouver le parent UIViewController.
Pour utiliser ce code, ajoutez-le dans un nouveau fichier de classe (j'ai nommé le mien "UIKitCategories") et supprimez les données de classe ... copiez le @interface dans l'en-tête, et le @implementation dans le fichier .m. Ensuite, dans votre projet, #import "UIKitCategories.h" et utilisez dans le code UIView:
la source
UIView
est une sous-classe deUIResponder
.UIResponder
présente la méthode-nextResponder
avec une implémentation qui retournenil
.UIView
remplace cette méthode, comme décrit dansUIResponder
(pour une raison quelconque au lieu de inUIView
) comme suit: si la vue a un contrôleur de vue, il est renvoyé par-nextResponder
. S'il n'y a pas de contrôleur de vue, la méthode retournera le superview.Ajoutez ceci à votre projet et vous êtes prêt à démarrer.
A maintenant
UIView
une méthode de travail pour renvoyer le contrôleur de vue.la source
UIView
et leUIViewController
. La réponse de Phil M avec la récursivité est la voie à suivre.Je suggérerais une approche plus légère pour parcourir la chaîne de répondeurs complète sans avoir à ajouter une catégorie sur UIView:
la source
En combinant plusieurs réponses déjà données, j'expédie également dessus avec ma mise en œuvre:
La catégorie fait partie de ma fonctionnalité ARC bibliothèque statique que j'expédie sur chaque application que je crée. Il a été testé plusieurs fois et je n'ai trouvé ni problème ni fuite.
PS: Vous n'avez pas besoin d'utiliser une catégorie comme je l'ai fait si la vue concernée est une sous-classe de la vôtre. Dans ce dernier cas, mettez simplement la méthode dans votre sous-classe et vous êtes prêt à partir.
la source
Même si cela peut techniquement être résolu comme le recommande pgb , à mon humble avis , il s'agit d'un défaut de conception. La vue ne devrait pas avoir besoin de connaître le contrôleur.
la source
J'ai modifié de réponse afin que je puisse passer une vue, bouton, étiquette etc pour obtenir des parents est tout
UIViewController
. Voici mon code.Modifier la version Swift 3
Edit 2: - Extension Swift
la source
N'oubliez pas que vous pouvez accéder au contrôleur de vue racine pour la fenêtre dont la vue est une sous-vue. À partir de là, si vous utilisez par exemple un contrôleur de vue de navigation et que vous souhaitez y insérer une nouvelle vue:
Cependant, vous devrez d'abord configurer correctement la propriété rootViewController de la fenêtre. Faites ceci lorsque vous créez le contrôleur pour la première fois, par exemple dans votre délégué d'application:
la source
[[self navigationController] view]
c'est la (sous) vue "principale" de la fenêtre, larootViewController
propriété de la fenêtre doit être définie surnavigationController
laquelle contrôle la vue "principale" immédiatement.Bien que ces réponses soient techniquement correctes, y compris Ushox, je pense que la manière approuvée est de mettre en œuvre un nouveau protocole ou de réutiliser un protocole existant. Un protocole isole l'observateur de l'observé, un peu comme mettre une fente de courrier entre eux. En effet, c'est ce que fait Gabriel via l'invocation de la méthode pushViewController; la vue "sait" que c'est un protocole approprié pour demander poliment à votre navigationController de pousser une vue, puisque le viewController est conforme au protocole navigationController. Bien que vous puissiez créer votre propre protocole, il suffit d'utiliser l'exemple de Gabriel et de réutiliser le protocole UINavigationController.
la source
Je suis tombé sur une situation où j'ai un petit composant que je veux réutiliser, et j'ai ajouté du code dans une vue réutilisable elle-même (ce n'est vraiment pas beaucoup plus qu'un bouton qui ouvre un
PopoverController
).Bien que cela fonctionne correctement dans l'iPad (le se
UIPopoverController
présente, il n'est donc pas nécessaire de faire référence à aUIViewController
), faire fonctionner le même code signifie soudainement référencer votrepresentViewController
depuis votreUIViewController
. Un peu incohérent, non?Comme mentionné précédemment, ce n'est pas la meilleure approche pour avoir de la logique dans votre UIView. Mais il semblait vraiment inutile d'envelopper les quelques lignes de code nécessaires dans un contrôleur séparé.
Quoi qu'il en soit, voici une solution rapide, qui ajoute une nouvelle propriété à n'importe quel UIView:
la source
Je ne pense pas que ce soit une "mauvaise" idée de savoir qui est le contrôleur de vue dans certains cas. Ce qui pourrait être une mauvaise idée est de sauvegarder la référence à ce contrôleur car elle pourrait changer tout comme les superviews changent. Dans mon cas, j'ai un getter qui traverse la chaîne de répondeurs.
//.h
//.m
la source
La boucle la plus simple pour trouver le viewController.
la source
Swift 4
(plus concis que les autres réponses)
Mon cas d'utilisation pour lequel je dois d'abord accéder à la vue
UIViewController
: j'ai un objet qui s'enroule autourAVPlayer
/AVPlayerViewController
et je souhaite fournir uneshow(in view: UIView)
méthode simple qui s'intègreAVPlayerViewController
dansview
. Pour cela, j'ai besoin d'accéderview
aux fichiersUIViewController
.la source
Cela ne répond pas directement à la question, mais fait plutôt une hypothèse sur l'intention de la question.
Si vous avez une vue et que dans cette vue, vous devez appeler une méthode sur un autre objet, comme par exemple le contrôleur de vue, vous pouvez utiliser le NSNotificationCenter à la place.
Créez d'abord votre chaîne de notification dans un fichier d'en-tête
Dans votre vue, appelez postNotificationName:
Ensuite, dans votre contrôleur de vue, vous ajoutez un observateur. Je fais cela dans viewDidLoad
Maintenant (également dans le même contrôleur de vue) implémentez votre méthode copyString: comme illustré dans le @selector ci-dessus.
Je ne dis pas que c'est la bonne façon de faire cela, cela semble juste plus propre que de remonter la chaîne des premiers intervenants. J'ai utilisé ce code pour implémenter un UIMenuController sur un UITableView et transmettre l'événement à l'UIViewController afin que je puisse faire quelque chose avec les données.
la source
C'est sûrement une mauvaise idée et une mauvaise conception, mais je suis sûr que nous pouvons tous profiter d'une solution Swift de la meilleure réponse proposée par @Phil_M:
Si votre intention est de faire des choses simples, comme afficher une boîte de dialogue modale ou suivre des données, cela ne justifie pas l'utilisation d'un protocole. Personnellement, je stocke cette fonction dans un objet utilitaire, vous pouvez l'utiliser à partir de tout ce qui implémente le protocole UIResponder comme:
Tout le crédit à @Phil_M
la source
Peut-être que je suis en retard ici. Mais dans cette situation je n'aime pas la catégorie (pollution). J'adore cette façon:
la source
Solution plus rapide
la source
sequence
bit). Donc, si "swifty" signifie "plus fonctionnel", alors je suppose que c'est plus rapide.Version mise à jour pour swift 4: merci pour @Phil_M et @ paul-slm
la source
Version Swift 4
Exemple d'utilisation
la source
Deux solutions à partir de Swift 5.2 :
return
mot - clé maintenant 🤓Solution 1:
Solution 2:
la source
À la réponse de Phil:
En ligne:
id nextResponder = [self nextResponder];
si self (UIView) n'est pas une sous-vue de la vue ViewController, si vous connaissez la hiérarchie de self (UIView), vous pouvez également utiliser:id nextResponder = [[self superview] nextResponder];
...la source
Ma solution serait probablement considérée comme un peu bidon, mais j'ai eu une situation similaire à mayoneez (je voulais changer de vue en réponse à un geste dans un EAGLView), et j'ai obtenu le contrôleur de vue de l'EAGL de cette façon:
la source
EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
.ClassName *object
- avec un astérisque.Je pense qu'il y a un cas où l'observé doit informer l'observateur.
Je vois un problème similaire où l'UIView dans un UIViewController répond à une situation et il doit d'abord dire à son contrôleur de vue parent de masquer le bouton Précédent, puis, une fois terminé, dire au contrôleur de vue parent qu'il doit se sortir de la pile.
J'ai essayé cela avec des délégués sans succès.
Je ne comprends pas pourquoi cela devrait être une mauvaise idée?
la source
Un autre moyen simple consiste à avoir votre propre classe de vue et à ajouter une propriété du contrôleur de vue dans la classe de vue. Habituellement, le contrôleur de vue crée la vue et c'est là que le contrôleur peut se définir sur la propriété. Fondamentalement, c'est au lieu de chercher (avec un peu de piratage) le contrôleur, d'avoir le contrôleur pour se définir sur la vue - c'est simple mais logique car c'est le contrôleur qui "contrôle" la vue.
la source
Si vous n'allez pas le télécharger sur l'App Store, vous pouvez également utiliser une méthode privée d'UIView.
la source
la source
Pour obtenir le contrôleur d'une vue donnée, on peut utiliser la chaîne UIFirstResponder.
la source
Si votre rootViewController est UINavigationViewController, qui a été configuré dans la classe AppDelegate, alors
Où c requis la classe de contrôleurs de vue.
USAGE:
la source
Il n'y a pas moyen.
Ce que je fais est de transmettre le pointeur UIViewController à l'UIView (ou un héritage approprié). Je suis désolé de ne pas pouvoir vous aider avec l'approche IB du problème car je ne crois pas en IB.
Pour répondre au premier commentateur: parfois, vous avez besoin de savoir qui vous a appelé car cela détermine ce que vous pouvez faire. Par exemple, avec une base de données, vous pouvez avoir un accès en lecture seule ou en lecture / écriture ...
la source