Compatibilité entre version xcode 4.2 et xcode 4.6.2
Bonjour,
J' utilise la nouvelle version de xcode 4.6.2 depuis hier. J' essaie de mettre à jour une app faite avec la version de xcode 4.2 mais j' ai un message d' erreur sur un code tout simple qui permet d' afficher un point dans une geolocalisation. ça marchait sur l' anvcienne version mais sur la nouvelle j' ai un triangle jaune qui est affiché comme on peut voir sur le fichier joint.
Quelqu' un peut il m' aider ?
Autre problème, lorsque je lance un projet fait avec l' ancienne version et devant être affiché dans le simulateur en horizontal, l' iphone est bien à l' horizontal mais le xib est affiché en vertical.
D' où cela vient t il ?
Merci d' avance.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Et qu'est ce qu'il te donne comme message d'avertissement ?
Pour le XIB, il suffit de le retourner pour le voir à l'horizontale.
J' ai essayé en retirant IBOutlet devant CLLocationnCoordinate2D et le warning disparait. Je met le fichier image mais je pense que c' est parce que le compilateur est plus précis qu' avant, et étant donné que CLLocationnCoordinate2D n' est pas un IBOutlet il mettait un warning.
Par contre pour le xib j' avais déjà mis à l' horizontal dans la fenetre aproprié mais lorsque je lance le simulateur, l' iphone apparait à l' horizontal mais à l' intérieur c' est afficher en vertical donc tout est à 90°.
Je precise que l' application est une mise à jour faite avec xcode 4.2.
Tout fonctionne bien lorsque je crée une nouvelle application dans xcode 4.6.2 mais lorsque j' ouvre une application faite avec une version anterieur il y a ce probleme horizontale.
Effectivement. J'aurais du réagir avant.
Un IBOutlet doit être une référence à un objet Objective-C afin que tout fonctionne correctement : gestion mémoire, archivage, KVC, KVO, Binding, ...
CLLocationCoordinate2D est un type scalaire C, ce n'est pas un objet Objective-C.
Heu non pour être précis, un IBOutlet doit être une référence à un objet car le mot clé "IBOutlet" ne sert qu'à faire en sorte qu'on puisse y connecter un objet dans InterfaceBuilder, donc un IBOutlet sur un type scalaire (qui ne peut être instancié par un XIB) n'a aucun sens.
Cela n'a donc rien à voir avec la gestion mémoire, le KVC ou le KVO.
Gestion mémoire, je me suis peut-être avancé.
Mais tu es sûr qu'il n'y a pas de KVC/KVO dans les Bindings ?
Heu jp tu confondrais pas IBOutlets et bindings ?
Les bindings utilisent le KVC et le KVO, oui on est d'accord, mais là on parlait d'outlets, et pas de bindings
Hello,
Apple Doc:
The type qualifier IBOutlet is a tag applied to an property declaration so that the Interface Builder application can recognize the property as an outlet and synchronize the display and connection of it with Xcode.
C'est surtout que je ne rappelle plus trop comment on définit les Bindings sous IB. ça fait quelques années que je n'ai plus développé pour OSX.
D'après tes explications on les définit directement sur des propriétés d'objets qui ne sont pas nécessairement des outlets. C'est ça ?
Ensuite pour la gestion mémoire. Là aussi je ne sais pas trop comment ça marche sous le capot :
- si à la lecture d'un XIB, Cocoa va d'abord lire et initialiser tous les objets qui s'y trouvent, puis ensuite seulement faire les connexions entre objets en utilisant les outlets, alors outlet et gestion mémoire n'ont effectivement rien à voir
- si à la lecture d'un XIB pour initialiser un contrôleur, le bazar ne va instancier que les objets connectés au contrôleur (par outlet donc), alors ça a un peu à voir avec la gestion mémoire (car pour moi la création d'un objet a un peu à voir avec la gestion mémoire)
Sachant comment fonctionne l'archivage sous Cocoa, j'aurais tendance à penser que c'est le second fonctionnement qui est le bon.
Les bindings se définissent le plus souvent dans l'onglet éponyme des inspecteurs IB, celui dont le raccourci clavier est ⌘⎇7..
À première vue les objets sont désarchivés et instanciés puis les connections sont faites.
1) It loads the contents of the nib and any referenced source files into memory
2) It unarchives the nib object graph data and instantiates the objects....
3) It reestablish all connections (actions, outlets and bindings) between objects in the nib file...
.
Et c'est là qu'on découvre que les outlets ça a à voir avec le KVC et le KVO.
Ce n'est pas gentil pour Ali ce que tu viens de faire là !!
Je confirme, je n'aurai pas fait mieux que la doc citée par Laudema (mon futur disciple ? ^^)
Quand un XIB est désarchivé, tous les objets qu'il contient sont instanciés, leurs propriétés configurés en fonction de ce que tu as réglé comme propriétés dans les palettes d'inspecteur de chaque objet, puis il établit toutes les connections.
Tu peux tout à fait charger des objets d'un XIB même s'il n'y a aucun IBOutlet de connecté dans le NIB (et encore heureux).
C'est comme ça par exemple qu'on charge typiquement une UITableViewCell customisée via un XIB par exemple.
- On peut ainsi appeller [[NSBundle mainBundle] loadNibNamed:@toto owner:nil options:0] qui va charger toto.nib en mémoire et le désarchiver (donc instancier tous ses objets et faire les connections, sauf que dans notre exemple y'a aucune connection) et retourner un NSArray de tous les top level objects instanciés.
- On peut aussi utiliser la classe NSNib/UINib pour charger le NIB en mémoire une seule fois puis l'instancier (le désarchiver) ensuit plusieurs fois si on a besoin de plusieurs instances et qu'on ne veut pas avoir à charger le NIB en mémoire à chaque fois...
Quand tu affectes une propriété, en particulier via son setter, cela génère toujours une notification KVO, via les willChangeValueForKey/didChangeValueForKey. De sorte que si tu as un observeur sur cette propriété, alors la méthode "observeValueForKeyPath:..." va être appelée dessus, laissant l'observeur agir en conséquence.
C'est le principe même du KVO : quand on change la valeur d'une propriété, une notif est envoyée, et ceux qui observent cette notification sont donc informés du changement.
- Les bindings sont basés là dessus pour faire en sorte de synchroniser 2 KeyPaths et faire en sorte qu'ils soient toujours cohérents, que quand le keyPath observé change, cela change la valeur du 2e keyPath qui se base dessus. Mais y'a pas que les bindings qui utilisent le KVO.
- Les IBOutlets sont des propriétés comme les autres, et ne dérogent pas à la règle que je viens d'expliquer : c'est à dire que si tu connectes un objet à un IBOutlet dans IB, cela fait exactement comme si tu avais affecté la propriété par code juste après l'instanciation des objets par le XIB. Donc entre autres cela émet une notification KVO pour que les éventuels observeurs de cette propriété soient informés de son changement... mais tout comme la même notification KVO est émise si tu fais cette affectation de la propriété par code.
En bref, pour rappeler les définitions :Que tu connectes la propriété "dataSource" de ta TableView à un objet via son IBOutlet dans IB, ou que tu écrives "tableView.dataSource = x" par le code, cela émettra une notification KVO dans tous les cas. Cela n'est en rien lié aux IBOutlets, c'est le mécanisme normal d'un setter de propriété, que cette propriété soit un IBOutlet ou une propriété affectée par code n'y change rien. Cet envoi de notif KVO est mentionné dans la doc juste pour rappel, mais c'est pas propre aux IBOutlet, d'ailleurs c'est pour cela qu'il y a un lien vers la doc générique de KVO qui n'est pas propre aux IBOutlets...
- KVO (Key-Value Observing) : mécanisme qui fait que quand on change la valeur d'une propriété, une notification est envoyée aux objets qui se sont indiqués comme observeurs de cette propriété, pour qu'ils soient informés du changement et puissent exécuter du code en conséquence
- KVC (Key-Value Coding) : mécanisme qui permet d'affecter des propriétés de façon générique en passant leur nom (sous forme de NSString) plutôt que d'accéder à la propriété directement. Permet également d'utiliser des "KeyPath", pour faire référence à des propriétés de propriétés etc et faire donc des appels en chaà®ne aux getters. Mais le principe est vraiment d'accéder à une propriété en passant son nom sous forme de chaà®ne
- Binding : système permettant de faire en sorte qu'une propriété X d'un objet soit calculé d'après la valeur d'une propriété Y d'un objet, et surtout que dès que Y change, X soit recalculé, de sorte que X et Y soient toujours en phase. Les bindings utilisent le mécanisme de KVO pour observer les changements de Y, et le mécanisme de KVC pour affecter la nouvelle valeur à X.
- IBOutlet : simple mot clé qui permet d'exposer une propriété de sorte qu'elle soit visible dans IB et qu'on puisse la connecter à un autre objet directement via IB, plutôt que d'affecter cette propriété par code. Cette affectation est faite lors de la phase de désarchivage du XIB, et utilise KVC pour affecter la propriété à partir de son nom (puisque c'est une NSString décrivant le nom de la propriété qui est stocké dans le XML du XIB ou dans le NIB). En pratique partir d'un objet A et connecter son IBOutlet X à un objet B via IB revient exactement au même que de faire la même affectation A.X = B via le code, et a donc les mêmes conséquences, y compris entre autres émettre une notification KVO, de sorte que si un objet s'est inscrit comme observeur de la propriété X de l'objet A, il soit notifié que cette propriété a changé de valeur et est maintenant affecté à la nouvelle valeur B.
Au final, IBOutlet et Bindings n'ont rien à voir, même si tous les deux utilisent KVC pour faire leur travail, mais c'est tout.A côté de ça, quand on affecte une propriété à une nouvelle valeur (via son setter) cela déclenche une notification KVO. Mais cela n'est en rien lié au fait que la propriété est un IBOutlet (et donc que l'affectation se fera par le mécanisme de désarchivage d'un XIB) ou pas (et que l'affectation sera faite par code).
Un IBOutlet n'est rien, à part pour IB qui les "voit". Si tu ne mets pas IBOutlet devant dans leur fichier de déclaration tu ne vois pas ton textField ou ta vue dans IB.
Sinon il se définit comme rien dans NSNibDeclaration.h
ça y est Ali je crois que j'ai compris pourquoi tu penses que je confonds tout.
Je me suis relu. Il y a trop d'implicite dans mon post #4.
J'aurais du écrire :
Un IBOutlet doit être une référence à un objet Objective-C car ce mot clé est utilisé pour définir la valeur de la propriété à un objet défini dans un XIB (ou un storyboard). Un fichier XIB ne peut contenir que des objets Objective-C pour que tout fonctionne correctement lors de sa lecture : création de l'objet (à la place de "gestion de la mémoire" dans mon post), désarchivage (à la place de "archivage" dans mon post), KVC. D'ailleurs il est impossible d'y mettre autre chose que des objets Objective-C.
En fait seule la première partie de la phrase est utile pour répondre à la question (ton post #5 donc).
OK donc pour supprimer le KVO qui n'est pas directement utilisé lors de la lecture d'un XIB.
OK aussi pour supprimer les Bindings si tu dis que ça n'a rien à voir avec les objets inclus dans un XIB. De toutes façons ça n'apporte rien de plus pour répondre à la question de J889.
- "gestion mémoire" au lieu de "instanciation"
- KVC/KVO : Je ne vois pas trop pourquoi tu as introduit ces 2 termes dans la conversation pour expliquer le principe des IBOutlets ou le fait que cela n'ait pas de sens d'anoter du mot IBOutlet une propriété non-objet... D'autant qu'on peut tout à fait faire du KVC et du KVO sur des propriétés non-objet (KVC se chargeant du boxing/unboxing au besoin, en plus)
Au final, j'espère que dans ton bouquin tu t'emploies à utiliser les bons termes et à pas mélanger les pinceaux comme ça[$]"archivage" au lieu de son antonyme "désarchivage" (au passage, on peut mettre des types atomiques dans une NSArchive donc ce n'est pas trop le problème, d'ailleurs dans un NIB y'a plein de nombres et valeurs atomiques pour les valeurs de certaines propriétés des objets ou quoi, c'est juste que ça n'a pas de sens de "connecter" (au sens IBOutlet) une "valeur", tu vas pas "tirer un câble" vers un nombre)
Il me semble bien que lorsqu'on définit la valeur d'une propriété pour un objet dans un XIB, la valeur de cette propriété est initialisée par KVC sur l'instance lors de la lecture du XIB.
Au moment d'écrire mon post#4 je me suis dit "mais au fait ! pourquoi est-ce qu'il ne pourrait y avoir que des objets dans un XIB ?" et du coup dans mon post j'ai répondu à ma propre question plutôt qu'à la question initiale.
Ha ben non alors ! Et d'ailleurs c'est parce que tout est mélangé qu'il plait bien.
Et puis t'a qu'à l'acheter, comme ça tu sauras 8--)
Et si tu l'achètes je proposerai à l'éditeur un nouveau macaron pour la 4ème édition : "Même Ali l'a acheté". À la place de trucs inutiles du genre "Xcode 4", "iCloud", ... ::)
Justement ça répond justement pas non plus à ta propre question ^^
Ce n'est pas "parce que ça utilise le KVC pour affecter la valeur de l'outlet" que "ça explique pourquoi on ne peut mettre que des objets dans un XIB".
Le KVC fonctionne parfaitement avec des propriétés non-objet, puisqu'il gère automatiquement le boxing des valeurs scalaires et des structures (voir ici). Donc le fait que le désarchivage d'un XIB utilise le KVC pour affecter les propriétés (que ce soit les outlets ou les "Runtime Properties" ou autre) n'est pas la raison qui explique qu'un IBOutlet doit forcément être un objet et pas un scalaire ou une struct... la raison est que l'arbre d'un XIB ne contient que des objets, et qu'un IBOutlet est ensuite connecté à d'autres objets dans le XIB, en "tirant un câble" de l'outlet vers un objet... donc en fait c'est limite par définition.
Fais attention. Après je vais croire que tu confonds. Sauf erreur, je n'ai jamais écrit "... le KVC pour affecter la valeur de l'outlet".
Un exemple.
Je mets un UILabel dans un XIB. Je définis sa taille de police à 18. 18 est bien une valeur scalaire.
Je pense qu'il y a un p'tit coup de KVC pour affecter la valeur de cette propriété à l'instance de UILabel créée lors de la lecture du XIB.
Et je pense donc que ça répond pile-poil à ma question. Pourquoi ne peut-on mettre que des objets dans un XIB ? Pour pouvoir les instancier avec un p'tit coup (ou même plusieurs) de KVC.
Je ne suis pas sûr que quand tu définis la taille de police de ton UILabel dans le XIB cela soit affecté par KVC ensuite. A mon avis, c'est plutôt encodé via le mécanisme de <NSCoder> et "encodeDouble:forKey:" et décodé avec "decodeDoubleForKey:"... Parce qu'un UILabel sait comment s'archiver dans une NSArchive et dans un XIB et sait ce qu'il expose comme propriété dans l'inspecteur, etc.
Faudrait vérifier, pour le coup je ne fais que supposer que c'est avec NSArchiver je l'ai pas lu dans la doc, mais quand on regarde la tronche d'un fichier XIB et qu'on voit qu'il ressemble fortement à la tête d'une NSArchive...
Par contre pour les IBOutlets, comme ce n'est pas tout l'objet que tu as connecté à ton IBOutlet qui est réencodé avec un encodeObject:forKey: mais bien une connexion qui est faite après instanciation (désarchivage / déencodage de l'archive), et qu'en plus tu peux créer tes propres IBOutlets avec un nom de propriété quelconque, c'est fait avec du KVC.
Je ne vois toujours pas le rapport. On pourrait très bien imaginer qu'Interface Builder un jour permette de rajouter dans un XIB des éléments représentant des scalaires et pas des objets, et pouvoir tirer des connexions / lier des objets du XIB à ces scalaires représentés dans le XIB. Ca pourrait même être pratique, après tout il y a bien déjà d'autres éléments dans un XIB qui ne sont pas instanciés, comme les Proxy Objects (le plus connu étant File's Owner), le FirstResponder, ... tous ceux-là ne sont pas instanciés lors du désarchivage, donc pourquoi pas des scalaires. Mais ça n'empêcherai pas d'instancier les objets qu'il y a dans le XIB et de leur affecter ces valeurs scalaires par KVC. J'ai toujours du mal à voir la relation de cause à effet entre "le désarchivage des XIBs utilise du KVC à différents stades du désarchivage (dont la connexion des IBOutlets et pour les Custom Runtime Attributes)" et "donc c'est pour ça qu'on ne peut mettre que des objets dans un XIB". "L'utilisation du KVC" n'implique pas "il faut absolument utiliser que des objets", le KVC étant capable de faire du boxing/unboxing.
En bon français un outlet est une prise en électricité, une sortie en Hi-Fi, un magasin d'usine dans le commerce. Une excroissance qui permet à un objet d'afficher une propriété pour que d'autres s'en saisissent.
Un IBOutlet est un outlet visible dans IB.
Dans ton exemple l'outlet c'est le UILabel pas sa taille de police.
Historiquement les .nibs (avant d'être des .xib) repéraient, instanciaient et usaient des outlets quand les bindings n'étaient encore qu'à l'état de concept ou de projet.
OK. Ma réponse n'est pas convenable.
Alors quelle est la bonne réponse à la question "pourquoi ne peut-on mettre que des objets dans un XIB ?"
Pour en revenir au xib qui s' affiche verticalement. C' est parce que il n' ait pas possible de changer l' orientation de la windows qui se trouve dans MainWindow.xib en fait c' est seulement à l' entrée de l' application que l' orientation se fait mal. Il faudrait arriver à changer l' orientation de la windows ou alors faire aller l' application directement à la vue créé ensuite.
Il n'y a pas vraiment de bonne réponse à cette question, c'est limite par définition.
La réponse à la rigueur serait "parce que par définition un XIB c'est une archive d'objets". Un XIB représente un graphe d'objets, ayant chacun des propriétés et étant potentiellement interconnectés entre eux (tout comme une NSArchive, d'ailleurs). Un XIB n'est qu'une NSArchive au final, c'est à dire un graphe d'objets. C'est sa définition, c'est tout.
Tout comme la réponse à la question "pourquoi le mot clé IBOutlet ne peut être apposé qu'à côté d'une propriété ou ivar de type objet et pas un scalaire", bah c'est par définition, puisqu'un IBOutlet n'est là que pour permettre de connecter une propriété... à un objet. Si c'était une propriété scalaire, il n'y aurait pas trop de sens à faire une "connexion"en "tirant un câble", ça serait plutôt une entrée affichée dans l'inspecteur pour te permettre de lui donner une valeur à la limite.
Une propriété de type objet est toujours un pointeur, donc normal qu'on "tire un câble vers" un autre objet, cela correspond au principe du pointeur qui "pointe" sur un objet. Un scalaire n'est pas un pointeur, c'est une valeur directement, il n'y aurait pas trop de sens à "tirer un câble vers" une valeur, le bon sens est plutôt de donner la valeur directement dans l'inspecteur (ce que tu peux déjà faire via les "Custom Runtime Attributes" dans le XIB, d'ailleurs)
D'ailleurs moi ce que j'aurai bien aimé c'est qu'Apple propose un autre mot clé, disons IBProperty ou un truc comme ça, qu'on pourrait utiliser pour annoter les propriétés de type scalaire cette fois et pas objet, et qui permettrait d'exposer cette propriété dans l'inspecteur de l'objet, permettant d'affecter sa valeur directement dans IB (comme c'est le cas pour certaines propriétés standards d'objets standards d'UIKit, sauf que du coup là on pourrait exposer des propriétés de nos sous-classes persos). Un peu comme les IBOutlet exposent les propriétés de type objet et permettent de les connecter à d'autres objets dans le XIB, les hypothétiques IBProperty permettraient d'exposer les propriétés de type scalaire et de leur donner une valeur via l'inspecteur. Mais bon, IB ne propose pas encore ça, la seule manière de faire cela pour l'instant (donner une valeur aux propriétés scalaires des objets dans le XIB) est d'utiliser les "Custom Runtime Attributes" mais faut alors rentrer le nom à la main et pas se gourer, c'est pas exposé tout seul dans une section dédiée de l'inspecteur...
Si c'est lors de l'exécution de ton application, ce n'est sans doute pas dû à la mise à jour de Xcode ou du compilateur à proprement parler, mais au fait que tu dois sans doute maintenant tester dans le simulateur iOS6 et plus iOS4 ou iOS5. Les méthodes pour gérer l'orientation ont changé en iOS5 et en iOS6 et maintenant il n'y a que le rootViewController qui doit gère l'orientation et dispatch à ses childVC. Ca évite que ce soit trop le boxon. Du coup ton code était sans doute prévu pour iOS4 et/ou iOS5 mais tu n'as pas encore rajouté les méthodes nécessaires pour gérer la nouvelle façon de faire sous iOS6 (je te conseille alors d'aller regarder la vidéo de la session #11 de CocoaHeads Rennes, qui traite justement du sujet)
La réponse simple : parce que Interface Builder ne connaà®t que les objets (et les "medias") en bas à droite en dessous du panneau des inspecteurs.
Il a été conçu "comme ça" , comme une bibliothèque d'objets standards qu'on place selon ses besoins dans ce qui fera ton fichier .xib adapté à ton programme.
Dans ce sens la méthode actuelle de création d'un outlet en faisant glisser l'objet de la library sur l'interface puis un clic-droit de l'objet sur le .h du file owner est plus logique, à mes yeux, que de créer l'objet d'abord dans FileOwner puis le connecter dans IB.