[Résolu] UIImagePickerController sur plusieurs UIImageViews
busterTheo
Membre
Bonjour,
Je fais simple...
Je développe en swift sur Xcode 6.1.1
Je dois choisir 5 photos à partir de l'album avec un UIImagePickerController, à partir de 5 UIImageViews qui sont dans le storyBoard.
Comment récupérer la référence du UIImageView sur lequel je clique, au sein de la fonction suivante ?
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {}
Cela, afin d'assigner l'image sélectionnée dans le picker, au bon UIImageView.
Merci d'avance.
busterTheo
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Clique sur le bouton "Modifier" de ton post, puis sur le bouton "Utiliser l'éditeur complet" pour modifier le titre de ton topic.
Ah, super. Merci pour ta remarque. Je suis nouveau sur ce forum.
Et t'aurais pas une idée pour mon pb ?
J'exagère, hein... Mais bon, j'ai cherché depuis deux jours sur le web, et rien à ce sujet.
Je n'ai jamais utilisé UIImagePickerController, désolé !
En plus ça fait partie des classes qui sont apparues du temps où il n'y avait pas les blocks et que les delegate, donc quand une action était asynchrone comme ici (on a la réponse de savoir "quelle image est choisie" bien plus tard, quand l'utilisateur a sélectionné son image), on a la réponse via une méthode de delegate comme ici... donc un appel d'une méthode complètement autre part dans le code, dans une méthode qui n'est pas liée à la méthode où on a appelé le UIImagePickerController.
Ce qui fait qu'au final tu appelles ton UIImagePickerController dans une méthode donnée (méthode dans laquelle tu connais certainement ton UIImageView tapée) et tu as la réponse dans une autre méthode (la méthode de delegate), qui est indépendante et ne connais pas ton UIImageView.
Une solution Quick & Dirty est de garder la UIImageView tapée dans une @property avant d'afficher ton UIImagePickerController, et d'utiliser cette @property quand la méthode de delegate est appelée.
Une solution beaucoup plus clean est de wrapper le UIImagePickerController et sa méthode de delegate dans une petite classe qui encapsule toute cette mécanique avec des blocks, plutôt qu'avec des delegate.
Merci AliGator pour ta réponse précise. Mais je n'ai pratiquement rien compris (Chui un peu débutant - Mais je maà®trise les delegate, protocole, classe et autres, quand même).
En gros tu veux dire, que même avec des tags sur les UIImageViews, mis, soit dans le storyboard, soit dans le code, je ne peux pas récupérer le UIImageView sur lequel je clique ? ça craint quand même !
Effectivement, quand tu dis "méthode dans laquelle tu connais certainement ton UIImageView tapée", bien sûr, je l'ai fait avec un seul UIImageView et ça marche impec Logique. C'est la base.
Mais là , j'ai vraiment besoin, dans mon appli, de choisir 5 photos. Cela veut dire que je dois, enchainer un écran par choix de photos...
Lorsque tu dis "de wrapper le UIImagePickerController et sa méthode de delegate dans une petite classe qui encapsule toute cette mécanique avec des blocks, plutôt qu'avec des delegate", je ne comprend pas trop. Tu entend quoi par "blocks" ? Et, si cela n'est pas trop abuser, heu, t'aurais pas un exemple ? Parce que "et sa méthode de delegate" et "plutôt qu'avec des delegate", cela me confusionne un peu d;-)
En tout cas, encore merci pour le temps que tu as consacré à mon problème.
Je suis quand même étonné que cela soit si compliqué de picker plusieurs photos dans un même écran.
Enfin, je dois être encore un peu naà¯f sur les applis.
cordialement
busterTheo
Car là on ne connais pas ton niveau, donc on ne peut pas te répondre efficacement. Manifestement, j'ai préjugé par exemple que tu connaissais les blocks / closures alors que cela ne semble pas être le cas.
Enfin, ce n'est pas du tout difficile de picker plusieurs photos dans un même écran.
Ce qui est difficile, c'est que tu n'as qu'un seul et même delegate (ton ViewController) quel que soit le code qui te crée ton picker et le présente. Du coup, quand ta méthode de delegate est appelée, comme c'est le même delegate pour tout le monde, tu n'as pas moyen de différencier de quelle UIImageView ça vient, car c'est le même delegate pour tout le monde.
La solution que je proposais était d'avoir des delegate différents, et pour faire cela proprement, je proposais de faire un wrapper pour convertir la mécanique de delegate en mécanique de closure, + répandue de nos jours et encore + avec Swift.
Mais manifestement tu n'en n'es pas encore là , donc c'est sans doute un exercice trop compliqué pour toi. Et du coup la solution Quick & Dirty (de mettre de côté dans une property la UIImageView tapée avant d'afficher le picker, et récupérer cette UIImageView via la propriété dans la méthode de delegate) est beaucoup plus simple à mettre en place et peut te convenir dans un premier temps.
Rebonjour AliGator,
je viens de lire tes messages avant d'aller me coucher.
Tout d'abord, je vais faire comme tu m'as dit, je vais aller écrire un message dans le forum "Présentation des Membres". Demain.
Ensuite, je t'ai lu en travers, mais promis, demain j'étudie tes explications. En tout cas, ça a l'air top.
Tu dis vrai pour les blocks / closures. J'ai croisé les closures mais je n'ai pas approfondi.
Juste au passage, je n'ai pas construit avec des UIButton mais comme ça. Je pense que tu comprendras. On a le droit ?
En gros j'associe le UITapGestureRecognizer aux UIImageViews pour les relier à la function "choisirImage"
Puis la function choisirImage
Et la méthode du picker pour l'instant uniquement basée sur une seule imageView (la première - frontalPatientImageView)
Je ne te met pas la function scaledImageWithImage pour ne pas te surcharger, mais tu imagines...
Concernant la navigation, je suis dans un container avec une sideNav. C'est un peu compliqué à expliquer. Dis moi si tu préfères que je te joignes le projet total. Ce serait certainement plus simple. Mais je ne veux pas non plus t'accaparer. Déjà , je pense que je devrais creuser ton idée de "d'avoir des delegate différents".
En même temps, je crois aussi que ton idée de se servir d'un
me semble le plus simple, bien que je doive reconstruire tout cela.
IBAction ou plusieurs delegate ? That is the question d;-)
En tout cas merci encore. Tes explications me rassurent.
Cordialement.
busterTheo
Le seul truc qui manque donc dans ton code de ta méthode choisirImage c'est de stocker la recognizer.view dans une propriété de ton ViewController pour pouvoir la récupérer plus tard dans ta méthode de delegate. C'est tout. T'étais pas loin finalement.
---
(bon et quand tu utilises un GestureRecognizer penses à n'exécuter ton code que si "recognizer.state == .Ended" car l'action associée à un GestureRecognizer est exécutée pour tous ses états intermédiaires aussi alors que toi tu ne veux afficher ton picker que quand la gesture de tap est reconnue " mais bon ce détail n'a rien à voir avec ta question sur les UIImageView et les UIImagePickerController, c'est juste une précision sur les GestureRecognizer au passage)
Bonjour AliGator,
merci pour tes encouragements.
J'ai mieux compris le problème, et après quelques suées, je m'en suis sorti grâce à ton code et à tes explications. C'est génial.
Je vais donc mettre le sujet comme résolu (faut que je trouve où c'est...), et faire mes présentations dans forum "Présentation des Membres".
Encore merci. Je peux,maintenant que ma structure de base est prête, me consacrer à la suite (zooms images, UIControls, etc), et là c'est pas gagné. Mais j'ai quand même fait pas mal de p'tits codes grâce à des tutos. Et je devrais m'en sortir. Je viendrais sur le forum si je galère.
Cordialement.
busterTheo
Du coup c'est plutôt juste une convention que d'éditer le titre du sujet pour le modifier et rajouter à la main le "[Résolu]" devant le titre.
Pour éditer le titre du sujet, il suffit d'éditer le tout premier message de ce fil de discussion (bouton "Modifier" en bas du premier post de ce sujet), en prenant soin de passer ensuite en mode "Utiliser l'Editeur Complet" (pour pouvoir modifier non pas que le texte du post mais aussi donc son titre).
Ca veut dire que tu as une propriété sur tout ton ViewController alors qu'elle ne te sert et n'a de sens que quand tu es dans une certaine phase (entre le moment où le picker est affiché et celui où l'utilisateur a choisi une image), et que dans tous les autres cas cette propriété est là pour rien. C'est n'est pas terrible en terme de bonne architecture de code.
Bon pour ton cas ça passe parce que tu veux avancer, et que tu es débutant et va sûrement t'en contenter. Mais si on veut faire les choses bien il y a des solutions plus propres en terme de bonnes pratiques qui existent (mais qui nécessitent d'avoir un meilleur niveau, donc je ne vais pas m'étendre dessus). Parmi les solutions qu'on peut imaginer :
- associer ton objet UIImageView (avec les associatedObjects du runtime ObjC) à ton UIImagePickerController au moment où tu crées ce dernier. Comme ensuite dans ta méthode de delegate tu as accès à ce picker, tu peux alors en réextraire l'UIImageView associée pour la récupérer
- Créer un petit wrappeur qui va encapsuler toute la logique de picker + delegate dans un objet dédié, et permettre de fournir une closure à appeler quand la méthode de delegate est déclenchée. Ainsi grace à ce wrapper, tu auras une API qui utilise une closure et non plus des delegate, et tu pourras fournir directement au même endroit le code qui crée le picker et le code à exécuter quand l'utilisateur a choisi son image (plutôt que d'avoir le début du code dans ton IBAction et la fin dans ta méthode de delegate). Conséquence, tu auras accès aux mêmes variables locales, dont ta UIImageView que tu connais encore quand tu restes dans le code de ton IBAction.
- Utiliser des concepts de plus haut niveau, comme PromiseKit & co... qui finalement vu leurs concepts proposent déjà ce wrapper qui expose un completionBlock / une closure plutôt que de passer par les delegate
Bon, c'est peut-être encore un peu tôt si tu viens de t'y remettre pour te parler dès à présent de ces concepts haut niveau, mais c'est + pour que tu saches que sa existe et qu'il y a plus propre comme solution, quitte à ce que tu y reviennes plus tard quand tu seras + à l'aise.
Bon, j'ai mis le résolu. Et au fait, je me suis présenté.
Concernant tes remarques, j'achète, bien que je n'y comprenne pas grand chose. Je vais creuser tout ça. De toute les façons je dois faire un code hyper propre et conforme, car je dois livrer cette appli en septembre et il faut que Apple me la valide. Sans quoi, je suis dans la mouise.
Pour l'instant je crée de nombreux fichiers pour tester tous les trucs que je dois faire (zooms, controls, etc). Et là , je suis content d'avoir ce squelette qui fonctionne (en plus avec du coredata selon les codes du nouveau doc masterDetail d'Apple pour sauvegarder les données) pour y ajouter les nouvelles fonctionnalités sus-nommées.
En tout cas, merci pour tes recommandations sur ces concepts de haut niveau.
Je fonce sur google pour voir ce que c'est que ce truc "associatedObjects du runtime ObjC".
ça fait peur, ça sent le objC. Bon, on verra bien. d;-)
busterTheo
La solution la plus propre reste l'encapsulation de picker + son délégate dans un wrapper qui expose une closure pour avoir une API plus propre. Je suis même étonné qu'Apple n'ait pas fait évoluer L'API de UIImagePickerController de la s'utilise historique utilisant un délégate vers une API utilisant un completionBlock / une closure. Ils l'ont déjà fait pour d'autres classes (je pense à NSURLConnection par exemple) ils auraient pu le faire pour le picker aussi...
Bonjour Alligator,
Alors j'ai essayé de l'utiliser dans mon projet, plutôt que la méthode
que j'utilisais. J'avais déjà croisé cette info, mais comme je travaille avec une sideNav, et donc la partie de droite est modifiée par des
j'avais ce message d'erreur, bien que le projet se lance bien
J'étais donc resté sur ma première version, avec l'astuce (self.view.window?.rootViewController?) trouvée sur le web
par
En gros, on observe la sideNav, les push, l'enregistrement et l'update.
Voilà . Pour l'instant je ne pousse pas trop sur ces sujets, car j'ai beaucoup à faire encore.
Encore merci.
busterThéo
Il y a eu pas mal d'améliorations dans Swift 1.2, en particulier l'apparition de l'opérateur "as!".
- Avant dans Swift 1.0 et Swift 1.1 on n'avait que "as" et "as?", et l'opérateur "as" était utilisé à la fois pour les cast toujours possibles (comme quand tu castes un objet vers sa classe parente : par définition un objet Mammifère est forcément aussi un objet Animal donc le cast vers Animal marchera toujours) et les cast qui pouvait rater (à l'inverse un Animal n'est pas toujours un Mammifère donc un cast de Animal vers Mammifère peut échouer)
- Avec Swift 1.2 le nouvel opérateur "as!" permet de faire la distinction entre les 2 et de rendre les choses plus claires.
Quand j'appelle ma closure dans la méthode de delegate, avec self.completion(info), je passe le contenu de la variable "info" à ma closure "completion", comme quand tu passes un paramètre à une fonction (en Swift une closure et une fonction sont interchangeables, d'ailleurs).
Et du coup de l'autre côté quand tu fournis le code de ta closure à exécuter quand l'utilisateur a choisi l'image, il faut bien récupérer ce paramètre pour en faire quelque chose d'utile (en l'occurence en extraire la originalImage pour l'affecter à l'imageView). C'est à ça que sert le "{ imageInfo in ... }"
ah je ne savais pas qu'il y avait Xcode 6.3 et Swift 1.2.
Je suis la tête dans le code 24/24
J'ai peur de le télécharger... Je vais attendre un peu. Merci pour l'info
En général, surtout pour les débutants, je conseille d'attendre la version officielle plutôt que de tester la Beta. Mais dans ce cas je ferais bien une exception et te conseillerais bien de la télécharger et l'utiliser, car parmi toutes les nouveautés apportées par cette version, il y a en particulier une meilleure stabilité du compilateur Swift et aussi de meilleurs messages d'erreur (plus explicites ou qui sortent la bonne erreur), là où jusqu'à présent Xcode était connu pour ne pas être très clair sur certaines erreurs en Swift (genre te dire qu'il ne connaissait pas une méthode alors qu'en fait elle existait mais avait un paramètre qui n'avait pas exactement le bon type, etc)
Ah d'acord, mais je vais quand même attendre, vu mon niveau. Sans quoi t'as pas une idée pour ma demande d'astuce sur l'erreur “Presenting view controllers on detached view controllers is discouraged†expliquée dans mon précédent post ?
Cordialement.
busterTheo
Effectivement, la bêta n'existe pas sur l'AppStore.
Merci pour les infos