Cocoa & Objective-C : apprendre à marcher...
overmac
Membre
Suite aux remarques d'Eddy58, je vais donc essayer d'apprendre le couple Cocoa/Objective-C grâce aux tutoriels de Projet Oméga.
- Les trois premiers articles permettent de bien définir les bases et de comprendre comment fonctionne Cocoa.
- Le quatrième article intitulé : Construisez votre première application Cocoa permet quant à lui de montrer la puissance de Cocoa en créant une interface pour un éditeur de texte simple, comprenant un correcteur de syntaxe, la gestion des styles et plus encore sans taper une seule ligne de code.
- Le cinquième article : Donnez du corps à votre éditeur de texte pousse plus loin la création du programme en intoduisant du code source.
Or c'est à ce chapitre que commence les problèmes. J'ai créé la connection de l'outlet de NSTextView puis on me demande de retourner dans Xcode (page 8 ).
"Le fait de cliquer sur MyDocument.h provoque l'ouverture du fichier des interfaces de classe dans l'éditeur de texte. Un double-clic aurait provoquer son ouverture dans une fenêtre indépendante. Entre les accolades qui suivent la ligne @interface MyDocument : NSDocument ajoutez la déclaration de variable suivante : id IBOutlet textView. Vous vous apercevez que la variable d'instance porte le même nom que l'outlet elle même et qu'elle est affublée des types id et IBOutlet. "
Heu...là déjà je ne comprends pas trop bien pourquoi il faut rajouter tous ça. Quelqu'un pourrait-il m'expliquer ?
D'avance merci...
- Les trois premiers articles permettent de bien définir les bases et de comprendre comment fonctionne Cocoa.
- Le quatrième article intitulé : Construisez votre première application Cocoa permet quant à lui de montrer la puissance de Cocoa en créant une interface pour un éditeur de texte simple, comprenant un correcteur de syntaxe, la gestion des styles et plus encore sans taper une seule ligne de code.
- Le cinquième article : Donnez du corps à votre éditeur de texte pousse plus loin la création du programme en intoduisant du code source.
Or c'est à ce chapitre que commence les problèmes. J'ai créé la connection de l'outlet de NSTextView puis on me demande de retourner dans Xcode (page 8 ).
"Le fait de cliquer sur MyDocument.h provoque l'ouverture du fichier des interfaces de classe dans l'éditeur de texte. Un double-clic aurait provoquer son ouverture dans une fenêtre indépendante. Entre les accolades qui suivent la ligne @interface MyDocument : NSDocument ajoutez la déclaration de variable suivante : id IBOutlet textView. Vous vous apercevez que la variable d'instance porte le même nom que l'outlet elle même et qu'elle est affublée des types id et IBOutlet. "
Heu...là déjà je ne comprends pas trop bien pourquoi il faut rajouter tous ça. Quelqu'un pourrait-il m'expliquer ?
D'avance merci...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Un outlet est une liaison qui te permet de faire le lien entre ton code et tes objets d'interface graphique. Ici, le code déclare ton pointeur sur l'objet textView de ton fichier nib.
"id" spécifie qu'aucun type de classe n'est attribué a ton objet. Tu peux améliorer ta déclaration de pointeur car tu sais que l'objet est de classe NSTextView :
et ensuite, dans ton implémentation (.m), tu peux envoyer les messages que tu veux à ton objet, par exemple, ici, tu remplies ton textView avec du texte, par la méthode setString :
De plus, dans IB, ty ne peux pas te tromper par ex. en connectant un NSButton au lieu d'un NSTextField (il y a le petit "sens interdit" qui apparaà®t en bas de la fenêtre d'infos).
Donc dans mon fichier MyDocument.h, au lieu d'avoir :
Je peux obtenir :
?
Ok, sympa l'onformation?
Par contre, autre chose que je n'arrives pas à faire. A la page 9 du chapitre 5, on peut lire :
"Nous devons indiquer à Xcode que notre document est au format RTFD. Pour l'instant nous ne lui avons rien dit du format en termes de structure de données, ni ce qu'est l'extension du fichier ou sa signature. Pour ce faire, ouvrez l'onglet " Targets " et cliquez sur la cible SimpleTextEditor. Dans cette vue, cliquez sur l'onglet " Application Settings ".."
Or je ne trouve pas dans Targets la cible SimpleTextEditor mais le nom de mon programme c'est-à -dire éditeur. Lorsque je double-clique dessus je ne trouve pas, je ne trouve pas l'onglet Application Settings.
Où se trouve-t-il ?
Quand tu as créé ton projet, tu as dû l'appeler "éditeur" au lieu de "SimpleTextEditor" comme ça devrait être donné à titre d'exemple dans le livre. :P
Ta cible (target) correspond à l'appli que tu construis. Quand tu fais un double-clic dessus tu doir avoir une fenêtre intitulée : Target "éditeur" info. Il faut ensuite aller dans l'onglet "Properties" pour modifier le type de document associé à ton appli (ici, in fichier avec l'extension .rtfd).
L'exemple du livre a été sans doute fait avec une version précédente d'Xcode qui, lui avait des onglets sur le côté gauche si je me rappelle bien. ???
Effectivement, j'ai Xcode 1.5...
Heu..oui, je me suis un peu emballé....
C'est exactement comme tu me la décrit. Merci...
Je continu mon apprentissage.
- A la page 10, au verset Sauvegarde de données dans un fichier, on me demande de tapez le code suivant :
En m'expliquant :
"NSRange est une structure C standard de données - pas un objet - prédéfinie comme faisant partie du programme-cadre " Foundation " et qui est juste formée de deux nombres qui définissentune portée sous la forme " point de départ " et " longueur ". Nous pouvons créer une portée en utilisant la fonction NSMakeRange() - pas une méthode - comme montrée ci-dessus. Ici nous avons une portée qui commence à l'élément 0 et a une longueur égale au nombre total de caractèrescontenus dans le document. Cette longueur est obtenue en retournant l'objet NSTextStorage, qui est l'endroit où le texte est actuellement stocké, en l'associant à notre zone de texte, puis en lui demandant combien de caractères y sont stockés par l'emploi de la méthode " length ".
Nous devons alors convertir le texte contenu dans textView en un objet NSData tel que requis par le type de donnée retourné de la méthode dataRepresentationOfType :. La méthode RTFDFromRange: déclarée dans la super-classe de NSTextView, NSText, le fait justement. Elle prend une rangée (portée) comme argument. Dans notre cas, la portée comprend notre document en entier. Elle convertit le texte compris dans cette portée en donnée et les renvoie sous forme d'objet NSData. L'objet renvoyé par le message [textView RTFDFromRange:range] est alors juste retourné puis renvoyé comme l'objet NSData renvoyé par la méthode dataRepresentationOfType:"
Heu...quelqu'un pourrait-il m'expliquer dans un langage compréhensible pour moi ? Car j'ai pas tout compris...
- Ensuite à la page 11, dans le verset Ouverture de fichiers de donnée, je dois rédiger dans le fichier MyDocument.m :
et
Là aussi, on me donne des explications qui ne sont pas à la portée du premier néophyte venu. Si quelqu'un pouvait bien un peu développer...
- Pour finir, je compile et éxécute mon programme éditeur, je peux taper du texte, faire des Undo (Annuler) mais lorsque j'essaye de sauvegarder mon travail, j'obtiens bien la fenêtre d'enregistrement, je tape le titre de mon fichier, mais le petit bouton rouge en haut à gauche de la fenêtre reste avec le petit point dedans pour signaler que je n'ai pas enregistré. Impossible d'enregistrer et de trouver le fichier que je croyais avoir enregistré sur mon bureau.
Que faire ?
D'avance merci...
PS : je tiens quand même à remercier les gens qui prennent la peine de me lire et de m'aider, car je suis sûr qu'ils ont peut-être autre chose à faire que d'aider un plouc comme moi...encore merci...
Par exemple, dans le texte suivant : "macintosh", lorsque tu fais : NSMakeRange(5, 9), 5 correspond au 5è caractère et 9 au nombre total de caractères du mot. Tu obtiens donc "tosh".
Avec :
[[textView textStorage] length] te calcule automatiquement la longueur de ton texte que tu as saisi étant donné que cette longueur n'est pas fixe.
:-\\
En ce qui concerne la suite, je préfère me taire plutôt que de dire des co.....es, je ne suis pas assez calé sur les NSData. Mais d'après ce que j'ai compris, [textView RTFDFromRange:range] convertit le texte normal en RTFD.
As-tu bien renseigné les caractéristiques de ton document ?
Voir copie d'écran ci-joint. La rubrique Class doit porter le même nom que ton fichier .m où tu as écris ton code ci-dessus (ex : "myDocument").
[img]http:///Volumes/Documents/Users/favouille/Desktop/Image 1.jpg[/img]
[Fichier joint supprimé par l'administrateur]
un NSRange contient simplement un point de départ et une longueur et peut ainsi définir nimporte quelle sous série dans une série. Ici elle définit une série de caractère (dans le texte) qui sera consernée par le méthode RTFDFromRange. Et en l'occurence ici Tous les caractères de la textView (range = {0, longueur du texte} )
Par ailleurs les textView ne gère pas directement leur texte, c'est leur NSTextStorage qui leur est associé qui contient le texte.
Dans certaine méthodes la textView peut se charger d'obtenir elle même les infos de la textStorage comme dans "RTFDFromRange" mais souvent il te faut demander à la textView un pointeur sur le NSTextStorage afin de lui demander directement des détails comme pour "length". C'est vrai que ça aurait pu être cool que la textView sache qu'elle doit obtenir la longuer du texte dans son textStorage lorsqu'on lui envoie "length" ... mais bon c'est pas mal non plus de se familiariser avec la structure de la gestion des textes et textView sous Cocoa .
Par ailleurs "dataRepresentationOfType" attend un NSData pour "l'écrire" dans le fichier disque, c'est le rôle de "RTFDFromRange" de générer des datas à partir d'un texte enrichi (avec styles) pouvant également contenir des images.
Là c'est la manoeuvre inverse.
"loadDataRepresentation" te renvoie les datas lues dans un fichier.
Tu les mets de côtés dans une variable et tu renvoies Vrai si t'est content ou Faux si t'as eu un problème (ici si data n'existe pas)
En fait tu mets de côté les datas prceque tu ne peux les "rentrer" dans le textView que s'il existe ... donc après que le fichier nib soit totalement chargé.
Donc dans "windowControllerDidLoadNib" tu utilises les datas (qui sont en principe les datas d'un texte RTFD) pour "remplir" ta textView avec "replaceCharactersInRange: withRTFD:" de ton instance de textView (là encore la textView sait comment s'adresser elle même au textStorage ... ouf )
textView est bien le nom de ton outlet vers la NSTextView ? Pas de faute de frappe ? L'outlet est bien connecté ?
Si tout va bien de ce côté, mets un point d'arrêt dans ta méthode "dataRepresentationOfType" ne serait-ce que pour t'assurer qu'elle est bien appellée quand tu sauvegarde.
@+
Heureusement que tu es arrivé, j'avais un peu de mal avec mes explications ± foireuses D'ailleurs, c'est encore plus clair pour moi aussi....
C'est un plaisir
J'ai réctifier certaines choses mais maintenant, je ne peux plus créer de document : voir fichiers attachés
Bon maintenant essayons de récapituler : Dites-moi si ce que je pense est faux
- L'enregistrement :
D'abord il faut choisir la longueur à enregistrer. C'est le rôle de :
NSMakeRange = ordre de sélectionner une portion de texte
0 = début de texte
[[textView textStorage] length] = textView demande à textStorage pour connaà®tre la longueur.
Puis il faut enregistrer :
textView demande que range soit au format RTFD via RTFDFromRange et puisque range = NSMakeRange alors la partie sélectionnée sera au format RTFD.
La partie enregistrement est finie.
- Ouverture de fichiers de donnée
D'abord il faut voir si le fichier contient quelque chose. C'est le rôle de :
data = données lues dans mon fichiers
loadDataRepresentation:(NSData *)data = charge data
fileData et return fileData != nil signifie que si dans data, il n'y a pas de données, on envoie rien. Si il y a des données, on les enregistre temporairement dans fileData pour que un fois que mon fichier nib (la fenêtre de mon programme) soit chargé, on puisse les transmettre dans la fenêtre.
Ensuite, il faut envoyer les données du fichier dans le fenêtre du programme :
if ( fileData != nil ) = seulement si il y a des données
[textView replaceCharactersInRange:NSMakeRange(0, 0)withRTFD:fileData]; signifie que la partie sélectionnée lors de l'enregistrement est chargée dans textView. Par contre pourquoi ne pas mettre directement ce code ? :
[Fichier joint supprimé par l'administrateur]
Pas exactement:
TU demandes à TexView un pointeur sur son textStorage.
Puis TU demandes à ce textStorage la longuer de son contenu
La non plus, pas exactement:
Tu demande à TextView qu'il te renvoie son contenu au format RTFD.
Mais pas tout son contenu, seulement la portée que tu décris dans le NSRange (bon ici ta portée c'est tout le contenu mais quel interrêt de faire 2 fonctions, une pour tout renvoyer et une pour juste une portée quand il suffit d'utiliser la 2ème en définissant la portée sur tout le contenu ? )
Parceque le range sélectionnée précédemment n'est pas en cause ici.
C'est le range (la portée) des caractères devant être remplacés par ceux des datas qu'on te demande .
Et surtout, même si on en est qu'au chargement du nib, cette méthode attend un NSRange comme argument.
Donc, comme on est au chargement du nib, un NSRange de {0,0} fait l'affaire.
Dans tout autre cas tu peux aussi faire un range de {0, longueurStockéeDansLeTextStorage} pour remplacer la totalité du contenu d'une texView par celui qui vient d'être lu.
J'espère avoir pu t'éclaircir.
Oui, merci, donc cela signifie que le reste de ce que j'avais écrit était correct ?
Maintenant, il faut que je trouve la solution à mon problème de programme. Il ne veut toujours pas ouvrir un fenêtre lors du démarrage.
Oui, il me semble que t'as tout bon pour le reste
C'est un documente-Based-Application ?
Essaie voir avec "editeur" :P
- Lors de la sauvegarde de mon interface (chapitre 4), j'ai obtenu un massage d'erreurs (à noter que lors de ma première tentative, j'avais eu aussi cette fenêtre d'erreurs) : voir fichiers attachés.
- J'ai indiqué à SimpleTextEditor le type de format, c'est-à -dire RTFD. Pour ce faire, dans Xcode, dans l'onglet Tagets, j'ai double-cliqué sur SimpleTextEditor, puis j'ai écrit rtfd dans : Type, Extentions, et OS Types. Dans Name, j'ai écrit le nom de mon application. Mais j'ai laissé dans Class MyDocument.
- Lors de remplissage du code source :
Pour (NSData *)dataRepresentationOfType:(NSString *)aType, on me dit : // Insert code here to write your document from the given data. You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.. Donc, j'ai écrit :
Pour (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType on me dit // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. Donc, j'ai écrit :
Pour (void)windowControllerDidLoadNib:(NSWindowController *) aController on me demande // Add any code here that needs to be executed once the windowController has loaded the document's window. Donc j'ai écrit :
Mais maintenant, lors de la compilation et de l'éxécution du programme, j'obtiens 5 erreurs avec pour toutes ce message : error:parse error before "{" (ou "}") token. Et je ne sais pas comment les enlever ces erreurs (j'ai essayer de retaper le code source mais rien n'y fait).
[Fichier joint supprimé par l'administrateur]
Il faudrait voir le code dans son ensemble.
Pour ta sauvegarde de tes nibs, je te conseille de choisir la version la plus récente. Tu pourras bénéficier de quelques fonctionnalités supplémentaires, notamment des bindings si tu es sous 10.3 ce qui doit être le cas puisque tu as Xcode 1.5.
Evite de prendre la 10.1, il n'y a plus grand monde qui l'utilise.
voilà les codes sources de MyDocument : voir fichier attaché
[Fichier joint supprimé par l'administrateur]
Il faut vérifier cela....
Effectivement, le problème venait du fait que j'avais oublié dans le document MyDocument.h de mettre :
Mais il ne veut toujours pas enregistrer, je pense ne pas avoir mis les bonnes caractéristiques dans mon programme (comme me la conseillé Favouille). Je remet une capture d'écran des propriétés...
[Fichier joint supprimé par l'administrateur]
En fait l'appli ne pouvait rien enregistrer parce qu'elle n'avait pas de données à se mettre sous la dent. C'est chose faite en rajoutant un NSTextView et en recréant le lien approprié.
Si tu fais un double-clic sur le File's Owner du MyDocument.nib, tu constateras que j'ai rajouté un NSTextView. :P
Je t'envoie le projet modifié. J'ai viré le dossier Build qui prend trop de place.
[Fichier joint supprimé par l'administrateur]
Pour le NSData je vois mais pour Interface Builder, je ne vois pas ce qui manque. Pourrais-tu développer ?
Heu...je ne vois pas le NStextView rajouté mais j'ai vu que tu as mis un bouton fermer. Pourrais-tu là aussi m'expliquer le NStextView et le lien ?
Encore merci...
Normalement, tu as créé une fenêtre dans laquelle tu as dû glisser un NSTextView. Ensuite, il faut faire le lien entre le code et le nib.
Dans la fenêtre d'instances de ton nib, tu as 3 éléments :
- le File's Owner
- le First responder
- la fenêtre que tu as créé.
Tu fais un double-clic sur le File's Owner (cube bleu). Tu dois voir apparaà®tre dans l'onglet Classes : "MyDocument" sélectionné.
Tu vas dans le menu : Classes > Read MyDocument.h. Dans la palette des infos, tu verras apparaà®tre des outlets dont le fameux TextView. :P
Tu cliques à nouveau sur l'onglet "instances" pour revenir sur le File's Owner.
Tout en maintenant la touche CTRL enfoncée, tu trace un trait entre le File's owner et ton NSTextView. Tu cliques sur "connect" dans la fenêtre des infos et le lien est créé ! 8)
Voilà qui est réparé : voir fichier attaché
Voilà ce que j'obtiens : voir fichier attaché
[Fichier joint supprimé par l'administrateur]
Donc tu devrais avoir cela : 2è image
[Fichier joint supprimé par l'administrateur]