Lezioni Cocoa

141
Il programmatore che c'è in noi - Lezione 1 - DATI I DATI rappresentano le INFORMAZIONI che l’esecutore del programma (il computer) ha a disposizione per poter eseguire il programma stesso (DATI DI INPUT=dati in ingresso) e per generare dei risultati (DATI OUTPUT=Dati di uscita). Quindi se io ho 10 euro in tasca, e se una Mela costa 1 euro, quante Mele potro’ comprare ? Semplice, 10. Scomponiamo il problema in modo “informatico” DATI IN INGRESSO ( Dati Input) HO 10 EURO UNA MELA COSTA 1 EURO DATI DI USCITA (Dati Output) 10 MELE Possiamo inoltre dire che i DATI hanno un VALORE (10, 1) ed un TIPO (euro, mele) ed occupano uno SPAZIO Bene, in informatica abbiano la stessa identica problematica: I DATI HANNO UN TIPO, HANNO UN VALORE ed OCCUPANO UNO SPAZIO. TIPI DI DATI I tipi di dati con cui abbiamo a che fare durante la realizzazione di un programma sono: DATI DI TIPO NUMERICO DATI DI TIPO CARATTERE DATI DI TIPO LOGICO Esempi di dati NUMERICI, sono l’età (40), il costo di un tazza di Caffe’ (0.85), la temperatura invernale in Montagna (-12) Esempi di dati di TIPO CARATTERE, il mio nome “Francesco”, la sezione della classe scolastica alle elementari “C” Esempi di dati tipo LOGICO sono, ho gli occhi azzurri ? NO. (SI/NO) o (VERO/FALSO) ossia dati che possono assumere solo uno dei due valori (SI/NO – VERO/FALSO) VALORI I DATI possono contenere dei valori COSTANTI (es. il mio nome, il colore dei miei occhi, il valore di PI GRECO) o VARIABILI (l’età, il costo della tazzina di caffe’). SPAZIO OCCUPATO Una mela occupa piu’ spazio di una moneta di un euro. Ogni DATO che deve essere gestito dal programma occupa uno spazio delle memoria RAM del nostro Computer, la quantità di spazio occupata dal dato dipende dal TIPO DI DATO e non dal suo VALORE.

Transcript of Lezioni Cocoa

Page 1: Lezioni Cocoa

Il programmatore che c'è in noi - Lezione 1 - DATI I DATI rappresentano le INFORMAZIONI che l’esecutore del programma (il computer) ha a disposizione per poter eseguire il programma stesso (DATI DI INPUT=dati in ingresso) e per generare dei risultati (DATI OUTPUT=Dati di uscita). Quindi se io ho 10 euro in tasca, e se una Mela costa 1 euro, quante Mele potro’ comprare ? Semplice, 10. Scomponiamo il problema in modo “informatico” DATI IN INGRESSO ( Dati Input) HO 10 EURO UNA MELA COSTA 1 EURO DATI DI USCITA (Dati Output) 10 MELE Possiamo inoltre dire che i DATI hanno un VALORE (10, 1) ed un TIPO (euro, mele) ed occupano uno SPAZIO Bene, in informatica abbiano la stessa identica problematica: I DATI HANNO UN TIPO, HANNO UN VALORE ed OCCUPANO UNO SPAZIO. TIPI DI DATI I tipi di dati con cui abbiamo a che fare durante la realizzazione di un programma sono: DATI DI TIPO NUMERICO DATI DI TIPO CARATTERE DATI DI TIPO LOGICO Esempi di dati NUMERICI, sono l’età (40), il costo di un tazza di Caffe’ (0.85), la temperatura invernale in Montagna (-12) Esempi di dati di TIPO CARATTERE, il mio nome “Francesco”, la sezione della classe scolastica alle elementari “C” Esempi di dati tipo LOGICO sono, ho gli occhi azzurri ? NO. (SI/NO) o (VERO/FALSO) ossia dati che possono assumere solo uno dei due valori (SI/NO – VERO/FALSO) VALORI I DATI possono contenere dei valori COSTANTI (es. il mio nome, il colore dei miei occhi, il valore di PI GRECO) o VARIABILI (l’età, il costo della tazzina di caffe’). SPAZIO OCCUPATO Una mela occupa piu’ spazio di una moneta di un euro. Ogni DATO che deve essere gestito dal programma occupa uno spazio delle memoria RAM del nostro Computer, la quantità di spazio occupata dal dato dipende dal TIPO DI DATO e non dal suo VALORE.

Page 2: Lezioni Cocoa

Immaginiamo di avere una scatola delle scarpe, vuota. Se la riempio di Mele, supponiamo, ne riesco a far stare 8 Se la riempio di Ciliegie, ne riesco a far stare 1000 Ovviamente posso mischiare le cose, e mettere nella scatola un po’ di Mele e di Ciliegie. Bene, la MEMORIA RAM del nostro amato Computer è la SCATOLA DELLE SCARPE. Piu’ RAM abbiamo, piu’ la scatola è grossa. Piu’ la scatola è grossa piu’ riesco a farci stare dentro della roba. Addirittura, in alcuni casi, la scatola deve essere “un minimo” grande, altrimenti non riusciro’ a farci stare dentro neppure un solo oggetto (esempio UN ANGURIA!). Ogni qual volta metto qualcosa nella scatola, lo spazio che ho a disposizione diminuisce, in base allo spazio occupato dal nuovo oggetto appena inserito. In casi estremi, arrivo a riempire la scatola (provocando un enorme rallentamento delle operazioni del computer sino al blocco…). Quando noi dobbiamo indicare quanto spazio abbiamo a casa nostra in una stanza, lo facciamo ad esempio dicendo, 80 metri quadrati (non certo dicendo, ci stanno tre sedie, un divano e un tavolo). Usiamo quindi un sistema che è accessibile a tutti e che tutti sono in grado di capire, usiamo una unita’ di misura. Per dire quanta è grossa la scatola delle scarpe del mio Mac in questo momento ho bisogno di una unità di misura per esprimere tale valore (non posso certo usare i metri quadrati, peccato sarebbe stato interessante… dire il mio Mac ha 4500 Mq ed il tuo ?). Bene, l’unita’ di misura che si utilizza in informatica è il BYTE 1 BYTE (per ragioni storiche…) possiamo paragonarlo ad un CARATTERE Quindi quando usando il mio programma di videoscrittura preferito, scrivo CIAO significa che ho usato 4 BYTES della mia scatola delle scarpe (RAM) del mio computer. Come tutte le unità di misura esistono i multipli e i sottomultipli MULTIPLI 1024 BYTES => 1 KILOBYTES -> 1 Kb Mille 1024 Kb => 1 MEGABYTES -> 1 Mb Milioni 1024 Mb => 1 GIGABYTES -> 1 Gb Miliardi SOTTOMULTIPLI 8 Bits = 1 BYTE Se il nostro Computer ha 2 Gb Ram, significa che la scatola è grossa circa 2 miliardi di caratteri, ne avete di spazio per scrivere…:) Per capire quanta RAM ha il nostro computer, Mela e Informazioni su questo Mac.

Page 3: Lezioni Cocoa

Per i piu’ curiosi : lanciate Terminale (Applicazioni/Utilità) e digitare il comando top, vedrete quanta memoria ha il vostro computer e quanta memoria utilizzano le varie applicazioni in esecuzione. Per oggi è tutto, vi saluto, vi ringrazio per il responso che avete dato alla mia iniziativa e spero di essere stato sufficientemente chiaro nella spiegazione. Dalla prossima puntata, inizieremo a fare qualcosa con XCODE, quindi, per chi ha voglia , tempo ecc. scaricatelo dal sito della Apple.

Page 4: Lezioni Cocoa

Il programmatore che c'è in noi - Lezione 2 - DATI Nel precedente articolo ho dato le indicazioni relative a come “misurare” lo spazio occupato nella memoria del calcolatore utilizzando una nomenclatura non del tutto corretta come è stato giustamente suggerito da Paolo Portaluri. Dal link http://www.germinara.it/iMemory.zip potete scaricare un progetto in Cocoa (contenente sia l’applicazione sia i sorgenti) dove sono meglio chiarite le nomenclature. Il realtà tale progetto contiene anche le indicazioni relative all’argomento di oggi. I TIPI DI DATI BASE La volta scorsa ho semplicemente fatto una distinzione tra DATI DI TIPO NUMERICO DATI DI TIPO CARATTERE DATI DI TIPO LOGICO In realta’ le cose sono un po’ piu’ complicate, il motivo di tale complicazione è dovuta al fatto che la memoria Ram (la nostra famosa scatola delle scarpe) non è grande all’infinito e quindi piu’ riusciamo a ottimizzarne lo spazio meglio e’. Bene, avete vinto al superenalotto e quindi cambiare casa, andate in un supermercato e prendete un po’ di scatoloni di diverse dimensioni. A questo punto, a casa, dovete mettere la vostra roba, nei vari scatoloni. Cosa fate ? Cercate di ottimizzare l’uso delle scatole a disposizione riempiendole con gli oggetti piu’ indicati o per dirlo al contrario scegliete lo scatolone adatto al tipo di oggetto che dovra’ contenere. Ad esempio, non metterete un solo libro in uno scatolone enorme, oppure non strapperete un libro pur di farlo entrare in uno scatolone troppo piccolo. Bene, anche per la nostra Memoria Ram (e disco fisso ecc.) dobbiamo fare necessariamente una ottimizzazione. Questa ottimizzazione è possibile decidendo il tipo di dato idoneo per memorizzarne il futuro valore , se ad esempio devo memorizzare l’eta’ di una persona, mi sarà sufficiente usare un tipo di dati che consenta di contenere un valore tra 0 e 120, di conseguenza si tratta di un numero INTERO, in questo caso SENZA SEGNO (non ha senso dire che una persona ha -5 anni…) Se invece devo memorizzare quanti secondi sono passati da quando sono nato, ho bisogno di uno scatolone piu’ grosso (in quanto il numero da memorizzare sara’ notevolmente piu’ grande). Se devo memorizzare (=mettere nello scatolone) il valore di temperatura invernale in montagna probabilmente avro’ necessita di indicare un valore tra – 25 e 30, usando in questo caso anche il numero negativo (quindi il segno). Per farla breve, se devo memorizzare il costo del pieno della mia auto avro’ necessita di indicare un valore REALE ossia con i numeri decimali (es. 63,58 ). Tutto questo in “informatichese” si traduce in Tipi di Dati base i quali occupano una determinata dimensione nella nostra Ram ma potranno contenere solo determinati valori sia come tipo

Page 5: Lezioni Cocoa

(carattere, intero, reale, booleano) sia come LIMITI (ossia il valore minimo che posso far stare in quello scatolone ed il valore massimo). Il tipo di dati piu’ semplice è il char, che puo’ contenere un solo CARATTERE o un numero che a seconda se con o senza segno, potra’ essere compreso tra -128 e +127 oppure tra 0 e 255 1 char occupa 1 BYTE nella nostra memoria Ram Questo significa che se devo memorizzare l’eta’ di una persona potrei farlo usando un dato di tipo char in quanto il valore è compreso tra -128 e 127, è chiaro che se una persona ha 130 anni (beato lui…) non potremmo memorizzare la sua eta’. Se ad esempio devo memorizzare l’inziale del mio nome, allora va bene un char perche’ e’ un carattere (nel mio caso la F) Davanti al nome del tipo di dato, puo’ comparire un “modificatore” del tipo, che e’ una ulteriore parola da scrivere prima del nome del tipo e specifica ulteriori informazioni per il tipo di dato, ad esempio se e’ senza segno (unsigned) o con segno (signed). Tipi di dati base Nome Dimensione occupata Descrizione char - 1 BYTE Carattere o numero intero piccolo int - 4 BYTES Numero intero float - 4 BYTES Numero reale (decimali) singola precisione double - 8 BYTES Numero reale (decimali) doppia precisione La dimensione occupata è indicativa, puo’ variare in funzione del computer utilizzato. Per conoscere l’esatta dimensione occupata in memoria dal tipo di dato in linguaggio C si utilizza l’operatore sizeof(nomedeltipodidato) Quindi sizeof(char) mi dira’ quanto spazio occupa un char in memoria sizeof(double) mi dira’ quanto spazio occupa un double in memoria e cosi’ via. Modificatori Nome Descrizione signed Il numero intero è con segno unsigned In numero interno è senza segno long Il numero è molto grande (lungo) short Il numero è piu’ piccolo del normale (corto) Esempi unsigned char = vuol dire che puo’ contenere un valore tra 0 e 255, ma non piu’ i valori negativi unsigned long int = vuol dire un numero intero senza segno molto grande ovviamente se voglio sapere la dimensione occupata in memoria uso

Page 6: Lezioni Cocoa

sizeof(unsigned long int) Nel progetto allegato a questa puntata, trovate un programma con cui iniziare a giocare con queste nozioni. I piu’ curiosi, possono implementare il programmino che ho fatto, ad esempio, facendo calcolare la dimensione di tipi di dati composti con i modificatori sopra descritti. Spero non vi sia venuto il mal di testa…

Page 7: Lezioni Cocoa

Il programmatore che c'è in noi - Lezione 3 – XCODE Tutorial Oggi, visto che siamo a fine settimana, facciamo qualcosa di rilassante, vediamo come creare un progetto Cocoa con XCODE e creiamo insieme un piccolo programma per visualizzare i LIMITI dei valori che possiamo inserire nei vari tipi di dati che ho descritto nella lezione 2. Ovviamente si presume che Xcode sia stato installato sul proprio Mac.

- Individuiamo dove si trova l’applicazione XCODE

Page 8: Lezioni Cocoa
Page 9: Lezioni Cocoa

e la mandiamo in esecuzione, quindi scegliamo File. NewProject

Compare

Page 10: Lezioni Cocoa

E selezioniamo COCOA APPLICATION

A questo punto diamo il nome alla nostra applicazione, nel mio esempio limiti e scegliamo in quale cartella dovrà risiedere il progetto, quindi premiamo Finish.

Page 11: Lezioni Cocoa

Ci appare l’ambiente di lavoro di XCODE

Per verificare se tutto è a posto, creiamo la nostra applicazione (la prima ?...)

E se tutto e’ a posto, eccola!!! BCS (… è un mio modo di dire… Bella Come il Sole… )

Page 12: Lezioni Cocoa

Ovviamente non fa assolutamente nulla, pero’ ho gia una finestra e un menu. Andare a vedere dove è stato creato il progetto, e vedrete tutti i files che Xcode ha generato per il progetto. Quelli con estensione .m e .h sono il codice sorgente in ObjectiveC, mentre quelli .nib sono i files di risorsa (=di interfaccia) usati da interface builder per progettare l’interfaccia utente (le finestre, i bottono ecc.) Comunque rimando alla documentazione della Apple per maggior dettaglio, o eventualmente, postate un commento specifico su Tevac.

Page 13: Lezioni Cocoa

Visto che abbiamo accennato a Interface Builder ed alla interfaccia utente, ritorniamo in XCODE e con un doppio clic sul elemento MainMenu.nib attiviamo Interface Builder (IB) per andare a modificare la nostra finestra e iniziare a personalizzare la nostra applicazione.

Page 14: Lezioni Cocoa

Una volta lanciato Interface Builder, vi consiglio di attivare subito la visualizzazione dell’Ispettore degli oggetti tramite questo menu

e di disporre le varie finestre nel modo piu’ comodo per lavorarci

Ciccando sulla finestra (Window) vedremo cambiare le informazioni dell’Ispettore di oggetto, accertandosi che sia attivo per la nostra finestra (nella finestra dell’ispettore deve comparire il titolo NSWindow Inspector ) Andiamo a cambiare il nome della finestra dal generico Window in Limiti

Page 15: Lezioni Cocoa

Dopo l’invio il nome della finestra viene aggiornato

Per fare un po’ di pratica, diciamo che ha l’aspetto “metallico”

ed otteniamo

Page 16: Lezioni Cocoa
Page 17: Lezioni Cocoa

Dall’ispettore, è possibile modificare tutta una serie di impostazioni ciccando nella COMBOBOX, tra cui ad esempio la dimensione della finestra usando la voce Size della combobox.

L’ispettore ora si presenta con i seguenti dati

Page 18: Lezioni Cocoa

Provare a modificare i valori di w (larghezza) e h (altezza) e vedrete la finestra cambiare dimensione. Bene, posizioniamo ora degli oggetti di testo (etichette o label), in quanto Vogliamo far comparire nella nostra finestra delle indicazioni che scriviamo noi Oltre alla nostra finestra “metallizzata”, alla finestra dell’ispettore, abbiamo altre due finestre, una TOOL BAR e una che rappresenta il nostro oggetto MainMenu.nib Nella Tool bar, selezioniamo Cocoa-Text

e successivamente cliccliamo su una Label/Etichetta che vogliamo inserire nella nostra finestra “metallizzata” (esempio Small System Font Text)

Page 19: Lezioni Cocoa

e mantenendo premuto il tasto sinistro del mouse, trasciniamo la scritta sulla finestra metallizzata, quindi rilasciamo il tasto del mouse.

Page 20: Lezioni Cocoa

Una volta “lasciato cadere” l’oggetto testo, possiamo ciccarci sopra e spostarlo nella posizione a noi piu’ congeniale.

Page 21: Lezioni Cocoa

Mentre spostare l’oggetto selezionato, vedrete apparire delle linee guida che vi aiutano a disporre gradevolmente l’oggetto e rispettando le linee guida Apple relativamente a Acqua.

Per modificare invece il contenuto del testo, doppio clic e si scrive dentro (oppure si usa l’ispettore…)

Nel nostro esempio, cambiamo la dicitura in char max, in quanto l’idea per il nostro programma è quella di far scrivere accanto al tipo di dato il suo range di valori minimi e massimi (i sui limiti).

Dato che abbiamo diversi elementi da posizionare, conviene usare il “copia” e “incolla”, Mela-C e Mela-V, quindi riposiziono gli oggetti.

Page 22: Lezioni Cocoa

e cosi via sino a completare la finestra con tutte le informazioni che intendo gestire.

Page 23: Lezioni Cocoa

Ecco come si presenta la finestra al termine.

A questo punto passo a posizionare un altro tipo di oggetto, un campo di input. Sempre dalla tool bar, cocoa-text, trascino l’elemento che mi interessa nella finestra metallizzata

E lo lascio cadere…

Page 24: Lezioni Cocoa

Come al solito, provvedo a posizionarlo ed eventualmente a ridimensionarlo.

Quindi uso il solito Copia/Incolla per velocizzare le operazioni di creazione di oggetti analoghi.

Sino ad ottenere l’effetto desiderato

Page 25: Lezioni Cocoa

A questo punto, voglio che le dimensioni della finestra siano fisse, quindi non ridimensionabile dall’utente, allora da Ispettore imposto Min w/h e Max w/h al valore della dimensione corrente della finestra.

Giunti a questo punto dobbiamo creare un nostro OGGETTO, che ci consentirà di controllare la nostra finestra (o meglio i campi della nostra finestra) durante l’esecuzione del programma. Infatti, quando il programma sarà mandato in esecuzione, vorremmo far comparire a fianco della scritta char max il valore (es. 127) massimo che posso memorizzare in un dato di tipo char ecc. Per creare questo nostro oggetto “controllore” che chiameremo appunto ilControllore, dobbiamo usare la finestra MainMenu.nib.

Page 26: Lezioni Cocoa

Da tale finestra clicco sul tab CLASSES, e mi posiziono sull’oggetto NSObject.

Una volta evidenziato NSObject clic con il destro (=CTRL+CLIC se ho il mouse con solo tasto…credo…) E dal menu che compare scelgo Subclass NSObject

Page 27: Lezioni Cocoa

Viene creata una nuova voce, MyObject, che io provvedo a rinominare con il nome ilControllore come avevo anticipato.

Do invio

e selezionando il mio oggetto “ilControllore”, clic di destro (per far apparire il menu contestuale)

Page 28: Lezioni Cocoa

E questa volta scelgo, Instantiate ilControllore, ossia chiedo a Interface Builder di creare il mio oggetto in modo che io possa lavorarci sopra.

Ed eccomi accontentato. Ora ho nel MainMenu.nib anche un oggetto che si chiama ilControllore che è il mio oggetto appena creato. Ovviamente tale oggetto è al momento un contenitore Vuoto. Lo seleziono, ciccandoci sopra

e guardo cosa succede nella finestra dell’Ispettore.

Page 29: Lezioni Cocoa
Page 30: Lezioni Cocoa

Vedete che ClassName = ilControllore (il nome del mio oggetto) e che è un contenitore vuoto (0 Outlets e 0 Actions). Cosa deve fare il mio oggetto controllore ? Deve gestire il passaggio delle informazioni tra il mio programma sorgente e gli oggetti grafici (il testo, il campo di input, un pulsante ecc.) che io ho collocato sulla mia finestra. Nel nostro esempio, io voglio poter controllare da programma il campo Field Text che ho inserito a fianco dell’etichetta di testo “char max” e “char min”. Ovviamente questo andrebbe fatto per tutti i campi Text Field che abbiamo Posizionato nella nostra finestra metallizzata, ma io, in questo esempio lo faccio solo per i primi due… a voi fare poi gli altri… Per far conoscere al mio oggetto controllore l’oggetto Text Field (=rettangolo bianco) a fianco del testo char max, devo ciccare sul Tab Outlets nella finestra ispettore, relativamente all’oggetto “ilControllore” come visibile

Quindi premo ADD per aggiungere un Outlet che mi consentirà di accedere all’oggetto Text Field.

Page 31: Lezioni Cocoa

Viene creato un nuovo elemento myOutlet

Page 32: Lezioni Cocoa

che ovviamente provvedo a chiamare in un modo piu’ idone

dato che voglio tramite questo outlet gestire questo campo (char max) come anticipato prima, il campo che abbiamo trascinato in precedenza nella nostra finestra metallizzata (quello rettangolare bianco) è un oggetto Cocoa che si chiama NSTextField, puo’ essere usato sia come campo di input dati sia come campo di output. Ma impareremo a conoscerlo meglio nelle prossime puntate.

Page 33: Lezioni Cocoa

Nella colonna a fianco Outlet Name, c’e’ la colonna Type, che identifica di che tipo è l’oggetti A CUI SI RIFERISCE (o meglio si referirà… perche’ dovremo poi effettivamente collegarlo all’oggetto che abbiamo messo sulla finestra metallizzata). Nel nostro casco, scegliamo NSTextField dall’elenco che appare.

In modo da ottenere

Page 34: Lezioni Cocoa

Dato che in questo tutorial voglio gestire solo i primi due (char max e char min) rifaccio nuovamente l’operazione. (tale operazione deve essere fatta per CIASCUN oggetto che ho messo sulla finestra del quale voglio avere il controllo tramite il codice sorgente del programma).

Page 35: Lezioni Cocoa
Page 36: Lezioni Cocoa

Bene, finita questa fase, ritorno sulla finestra MainMenu.nib

Page 37: Lezioni Cocoa

seleziono Instances in modo da portarmi nella seguente modalità

Ora, sulla sinistra del nostro oggetto ilControllore, è comparso un punto esclamativo: esso indica che abbiamo degli outlets o delle actions da collegare. Quindi, colleghiamoli… L’operazione che stiamo per fare (tramite drag & drop) “collega” le outlets che abbiamo appena creato con i

Page 38: Lezioni Cocoa

rispettivi oggetti Cocoa che avevamo piazzato sulla finestra metallizzata.

Per fare un COLLEGAMENTO di una OUTLET Clic sull’oggetto presente in MainMenu.nib (ilControllore), premo il tasto CTRL e faccio CLIC, trascino il puntatore del mouse sopra l’oggetto che mi interessa collegare e lascio andare il tasto CTRL e il tasto del mouse L’ispettore si posiziona in questa modalità

Page 39: Lezioni Cocoa

A questo punto faccio un clic sul OUTLET che voglio collegare all’oggetto che ho precedentemente selezionato e premo CONNECT.

Quando è collegato, compare un pallino sulla sinistra, e nella colonna Destination compare l’oggetto NSTextField. Rifaccio l’operazione di collegamento anche per il secondo campo a fianco del testo char min (che sara’ collegato all’outlet limiteCharMin)

Page 40: Lezioni Cocoa

Se diamo uno sguardo al nostro oggetto ilControllore nella videata MainMenu.nib ora non ha piu’ il punto esclamativo.

Siamo quasi al dunque,… abbiate fede… Ora non ci rimane che chiedere a Interface Builder di creare per noi i files di sorgenti relativi al nostro oggetto ilControllore che abbiamo creato. Perche’ questo ? Semplice, noi vogliamo scrivere dei valori nei due NSTextField che abbiamo posizionato nella finestra metallizata e tali valori devono essere scritti dal nostro programma, quindi abbiamo bisogno dei files di programma (.m e .h) che rappresentano l’oggetto ilControllore. Tali files devono essere inclusi nel nostro progetto di xcode. Per far creare a Interface Builder i files necessari, selezioniamo CLASSES dalla finestra MainMenu.nib

Page 41: Lezioni Cocoa

Quindi selezioniamo il nostro oggetto ilControllore e facciamo comparire il menu contestuale (clic tasto destro del mouse)

Page 42: Lezioni Cocoa

Questa volta scegliamo CREATE FILES FOR ilControllore e compare

vedete che ha gia’ assegnato i nomi ai files .m e .h cre saranno creati e che saranno automaticamente aggiunti al progetto “limiti”. Non dobbiamo far altro che premere CHOOSE.

Bene, è giunto il momento di abbandonare Interface Builder, salviamo tutto e chiudiamo.

Page 43: Lezioni Cocoa

Ritorno si XCODE e mi ritrovo i files che sono stati aggiunti da Interface Builder

Page 44: Lezioni Cocoa

Bene, vediamo cosa c’e’ scritto dentro i files ilControllore.h e ilControllore.m, che sono parte dei sorgenti del nostro programma. Per vederne il contenuto, ciccate sul pulsante Editor nella barra strumenti

in modo da avere la seguente modalità di visualizzazione

Page 45: Lezioni Cocoa

Quello che vediamo è stato scritto in automatico (seguendo le nostre indicazioni…) relativamente all’oggetto ilControllore. Sono facilmente riconoscibili i due outlet che abbiamo in precedenza creato.

Il file ilControllore.m, invece non ha nessuna indicazione particolare. Per concludere il mio tutorial, volevo scrivere il valore max e minimo consentito per un tipo di dato char. Per fare questo, devo intercettare un particolare evento di Cocoa, che si chiama awakeFromNib.

Page 46: Lezioni Cocoa

In pratica, quando lancio il programma, il programma in automatico carichera’ in memoria il file NIB indicato e creera’ tutti gli oggetti presenti nel file NIB stesso (tra cui il nostro ilControllore). Quando questo avviene, l’applicazione avvisa tutti gli oggetti inviando loro un messaggio di tipo awakeFromNib appunto. (=risvegliato dal NIB) In questo modo, nel mio programma, io posso effettuare delle azioni non appena l’oggetto viene creato, nel caso specifico l’azione che io voglio fare è quella di scrivere un valore dentro l’oggetto NSTextField collegato all’outlet limiteCharMax. Per fare cio’ devo aggiunger il metodo awakeFromNib nel codice sorgente del mio oggetto ilControllore.c e quindi all’interno di tale metodo, ricavare il valore max e min consentiti per un char. Per ricavare tale valore, non faccio altro che usare i valori costanti definiti dal file limits.h (che potete cercare sul vostro Mac.) Questo è un pezzo di tale file #include <ppc/_limits.h> #define CHAR_BIT 8 /* number of bits in a char */ #define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */ #ifndef CLK_TCK #define CLK_TCK __DARWIN_CLK_TCK /* ticks per second */ #endif /* * According to ANSI (section 2.2.4.2), the values below must be usable by * #if preprocessing directives. Additionally, the expression must have the * same type as would an expression that is an object of the corresponding * type converted according to the integral promotions. The subtraction for * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values * are written as hex so that GCC will be quiet about large integer constants. */ #define SCHAR_MAX 127 /* min value for a signed char */ #define SCHAR_MIN (-128) /* max value for a signed char */ #define UCHAR_MAX 255 /* max value for an unsigned char */ #define CHAR_MAX 127 /* max value for a char */

Page 47: Lezioni Cocoa

#define CHAR_MIN (-128) /* min value for a char */ #define USHRT_MAX 65535 /* max value for an unsigned short */ #define SHRT_MAX 32767 /* max value for a short */ #define SHRT_MIN (-32768) /* min value for a short */ …. Quindi il valore massimo di un char è indicato dalla COSTANTE CHAR_MAX che vale 127 come visibile dal file. Dato che il valore è numerico, ed il campo che io ho messo nella finestra metallizzata è un NSTextField (campo di testo) lo devo convertire in testo. Per fare tale operazione, uso un oggetto Cocoa che rappresenta una stringa di caratteri NSString ed uso un suo metodo per convertire numeri in testo stringWithFormat Vedremo comunque meglio ed in dettaglio queste cose, in una prossima lezione. In pratica il codice che vado ad inserire dentro ilControllore.m Tra @implementation e @end è

Quindi effettuo le operazioni di conversione dati numerici in stringa

e dico alla mia outlet (che rappresenta il campo NSTextField char max) di che ora contiene una stringa che è il dato che interessa.

Page 48: Lezioni Cocoa

Ecco come si presenta il codice completo di ilControllore.m #import "ilControllore.h" @implementation ilControllore -(void) awakeFromNib{ NSString *unaStringa; unaStringa=[NSString stringWithFormat:@"%d", CHAR_MAX]; [limiteCharMax setStringValue:unaStringa]; unaStringa=[NSString stringWithFormat:@"%d", CHAR_MIN]; [limiteCharMin setStringValue:unaStringa]; } @end Ed ecco il risultato finale dell’applicazione e del tutorial.

Esercitatevi a fare tutti i passagi che ho descritto in modo da acquisire la necessaria manualità ed a familiarizzare con l’ambiente XCODE e Interface Builder. Per i piu’ intraprendenti: provare a completare l’applicazione facendo calcolare anche gli altri valori e rendendo i campi solo di OUTPUT.

Page 49: Lezioni Cocoa

Se volete potete anche inviarmi il vostro lavoro al termine, al mio indirizzo email. Francesco Germinara [email protected] www.germinara.it

Page 50: Lezioni Cocoa

Il programmatore che c'è in noi - Lezione 3 – XCODE Tutorial Oggi, visto che siamo a fine settimana, facciamo qualcosa di rilassante, vediamo come creare un progetto Cocoa con XCODE e creiamo insieme un piccolo programma per visualizzare i LIMITI dei valori che possiamo inserire nei vari tipi di dati che ho descritto nella lezione 2. Ovviamente si presume che Xcode sia stato installato sul proprio Mac.

- Individuiamo dove si trova l’applicazione XCODE

Page 51: Lezioni Cocoa
Page 52: Lezioni Cocoa

e la mandiamo in esecuzione, quindi scegliamo File. NewProject

Compare

Page 53: Lezioni Cocoa

E selezioniamo COCOA APPLICATION

A questo punto diamo il nome alla nostra applicazione, nel mio esempio limiti e scegliamo in quale cartella dovrà risiedere il progetto, quindi premiamo Finish.

Page 54: Lezioni Cocoa

Ci appare l’ambiente di lavoro di XCODE

Per verificare se tutto è a posto, creiamo la nostra applicazione (la prima ?...)

E se tutto e’ a posto, eccola!!! BCS (… è un mio modo di dire… Bella Come il Sole… )

Page 55: Lezioni Cocoa

Ovviamente non fa assolutamente nulla, pero’ ho gia una finestra e un menu. Andare a vedere dove è stato creato il progetto, e vedrete tutti i files che Xcode ha generato per il progetto. Quelli con estensione .m e .h sono il codice sorgente in ObjectiveC, mentre quelli .nib sono i files di risorsa (=di interfaccia) usati da interface builder per progettare l’interfaccia utente (le finestre, i bottono ecc.) Comunque rimando alla documentazione della Apple per maggior dettaglio, o eventualmente, postate un commento specifico su Tevac.

Page 56: Lezioni Cocoa

Visto che abbiamo accennato a Interface Builder ed alla interfaccia utente, ritorniamo in XCODE e con un doppio clic sul elemento MainMenu.nib attiviamo Interface Builder (IB) per andare a modificare la nostra finestra e iniziare a personalizzare la nostra applicazione.

Page 57: Lezioni Cocoa

Una volta lanciato Interface Builder, vi consiglio di attivare subito la visualizzazione dell’Ispettore degli oggetti tramite questo menu

e di disporre le varie finestre nel modo piu’ comodo per lavorarci

Ciccando sulla finestra (Window) vedremo cambiare le informazioni dell’Ispettore di oggetto, accertandosi che sia attivo per la nostra finestra (nella finestra dell’ispettore deve comparire il titolo NSWindow Inspector ) Andiamo a cambiare il nome della finestra dal generico Window in Limiti

Page 58: Lezioni Cocoa

Dopo l’invio il nome della finestra viene aggiornato

Per fare un po’ di pratica, diciamo che ha l’aspetto “metallico”

ed otteniamo

Page 59: Lezioni Cocoa
Page 60: Lezioni Cocoa

Dall’ispettore, è possibile modificare tutta una serie di impostazioni ciccando nella COMBOBOX, tra cui ad esempio la dimensione della finestra usando la voce Size della combobox.

L’ispettore ora si presenta con i seguenti dati

Page 61: Lezioni Cocoa

Provare a modificare i valori di w (larghezza) e h (altezza) e vedrete la finestra cambiare dimensione. Bene, posizioniamo ora degli oggetti di testo (etichette o label), in quanto Vogliamo far comparire nella nostra finestra delle indicazioni che scriviamo noi Oltre alla nostra finestra “metallizzata”, alla finestra dell’ispettore, abbiamo altre due finestre, una TOOL BAR e una che rappresenta il nostro oggetto MainMenu.nib Nella Tool bar, selezioniamo Cocoa-Text

e successivamente cliccliamo su una Label/Etichetta che vogliamo inserire nella nostra finestra “metallizzata” (esempio Small System Font Text)

Page 62: Lezioni Cocoa

e mantenendo premuto il tasto sinistro del mouse, trasciniamo la scritta sulla finestra metallizzata, quindi rilasciamo il tasto del mouse.

Page 63: Lezioni Cocoa

Una volta “lasciato cadere” l’oggetto testo, possiamo ciccarci sopra e spostarlo nella posizione a noi piu’ congeniale.

Page 64: Lezioni Cocoa

Mentre spostare l’oggetto selezionato, vedrete apparire delle linee guida che vi aiutano a disporre gradevolmente l’oggetto e rispettando le linee guida Apple relativamente a Acqua.

Per modificare invece il contenuto del testo, doppio clic e si scrive dentro (oppure si usa l’ispettore…)

Nel nostro esempio, cambiamo la dicitura in char max, in quanto l’idea per il nostro programma è quella di far scrivere accanto al tipo di dato il suo range di valori minimi e massimi (i sui limiti).

Dato che abbiamo diversi elementi da posizionare, conviene usare il “copia” e “incolla”, Mela-C e Mela-V, quindi riposiziono gli oggetti.

Page 65: Lezioni Cocoa

e cosi via sino a completare la finestra con tutte le informazioni che intendo gestire.

Page 66: Lezioni Cocoa

Ecco come si presenta la finestra al termine.

A questo punto passo a posizionare un altro tipo di oggetto, un campo di input. Sempre dalla tool bar, cocoa-text, trascino l’elemento che mi interessa nella finestra metallizzata

E lo lascio cadere…

Page 67: Lezioni Cocoa

Come al solito, provvedo a posizionarlo ed eventualmente a ridimensionarlo.

Quindi uso il solito Copia/Incolla per velocizzare le operazioni di creazione di oggetti analoghi.

Sino ad ottenere l’effetto desiderato

Page 68: Lezioni Cocoa

A questo punto, voglio che le dimensioni della finestra siano fisse, quindi non ridimensionabile dall’utente, allora da Ispettore imposto Min w/h e Max w/h al valore della dimensione corrente della finestra.

Giunti a questo punto dobbiamo creare un nostro OGGETTO, che ci consentirà di controllare la nostra finestra (o meglio i campi della nostra finestra) durante l’esecuzione del programma. Infatti, quando il programma sarà mandato in esecuzione, vorremmo far comparire a fianco della scritta char max il valore (es. 127) massimo che posso memorizzare in un dato di tipo char ecc. Per creare questo nostro oggetto “controllore” che chiameremo appunto ilControllore, dobbiamo usare la finestra MainMenu.nib.

Page 69: Lezioni Cocoa

Da tale finestra clicco sul tab CLASSES, e mi posiziono sull’oggetto NSObject.

Una volta evidenziato NSObject clic con il destro (=CTRL+CLIC se ho il mouse con solo tasto…credo…) E dal menu che compare scelgo Subclass NSObject

Page 70: Lezioni Cocoa

Viene creata una nuova voce, MyObject, che io provvedo a rinominare con il nome ilControllore come avevo anticipato.

Do invio

e selezionando il mio oggetto “ilControllore”, clic di destro (per far apparire il menu contestuale)

Page 71: Lezioni Cocoa

E questa volta scelgo, Instantiate ilControllore, ossia chiedo a Interface Builder di creare il mio oggetto in modo che io possa lavorarci sopra.

Ed eccomi accontentato. Ora ho nel MainMenu.nib anche un oggetto che si chiama ilControllore che è il mio oggetto appena creato. Ovviamente tale oggetto è al momento un contenitore Vuoto. Lo seleziono, ciccandoci sopra

e guardo cosa succede nella finestra dell’Ispettore.

Page 72: Lezioni Cocoa
Page 73: Lezioni Cocoa

Vedete che ClassName = ilControllore (il nome del mio oggetto) e che è un contenitore vuoto (0 Outlets e 0 Actions). Cosa deve fare il mio oggetto controllore ? Deve gestire il passaggio delle informazioni tra il mio programma sorgente e gli oggetti grafici (il testo, il campo di input, un pulsante ecc.) che io ho collocato sulla mia finestra. Nel nostro esempio, io voglio poter controllare da programma il campo Field Text che ho inserito a fianco dell’etichetta di testo “char max” e “char min”. Ovviamente questo andrebbe fatto per tutti i campi Text Field che abbiamo Posizionato nella nostra finestra metallizzata, ma io, in questo esempio lo faccio solo per i primi due… a voi fare poi gli altri… Per far conoscere al mio oggetto controllore l’oggetto Text Field (=rettangolo bianco) a fianco del testo char max, devo ciccare sul Tab Outlets nella finestra ispettore, relativamente all’oggetto “ilControllore” come visibile

Quindi premo ADD per aggiungere un Outlet che mi consentirà di accedere all’oggetto Text Field.

Page 74: Lezioni Cocoa

Viene creato un nuovo elemento myOutlet

Page 75: Lezioni Cocoa

che ovviamente provvedo a chiamare in un modo piu’ idone

dato che voglio tramite questo outlet gestire questo campo (char max) come anticipato prima, il campo che abbiamo trascinato in precedenza nella nostra finestra metallizzata (quello rettangolare bianco) è un oggetto Cocoa che si chiama NSTextField, puo’ essere usato sia come campo di input dati sia come campo di output. Ma impareremo a conoscerlo meglio nelle prossime puntate.

Page 76: Lezioni Cocoa

Nella colonna a fianco Outlet Name, c’e’ la colonna Type, che identifica di che tipo è l’oggetti A CUI SI RIFERISCE (o meglio si referirà… perche’ dovremo poi effettivamente collegarlo all’oggetto che abbiamo messo sulla finestra metallizzata). Nel nostro casco, scegliamo NSTextField dall’elenco che appare.

In modo da ottenere

Page 77: Lezioni Cocoa

Dato che in questo tutorial voglio gestire solo i primi due (char max e char min) rifaccio nuovamente l’operazione. (tale operazione deve essere fatta per CIASCUN oggetto che ho messo sulla finestra del quale voglio avere il controllo tramite il codice sorgente del programma).

Page 78: Lezioni Cocoa
Page 79: Lezioni Cocoa

Bene, finita questa fase, ritorno sulla finestra MainMenu.nib

Page 80: Lezioni Cocoa

seleziono Instances in modo da portarmi nella seguente modalità

Ora, sulla sinistra del nostro oggetto ilControllore, è comparso un punto esclamativo: esso indica che abbiamo degli outlets o delle actions da collegare. Quindi, colleghiamoli… L’operazione che stiamo per fare (tramite drag & drop) “collega” le outlets che abbiamo appena creato con i

Page 81: Lezioni Cocoa

rispettivi oggetti Cocoa che avevamo piazzato sulla finestra metallizzata.

Per fare un COLLEGAMENTO di una OUTLET Clic sull’oggetto presente in MainMenu.nib (ilControllore), premo il tasto CTRL e faccio CLIC, trascino il puntatore del mouse sopra l’oggetto che mi interessa collegare e lascio andare il tasto CTRL e il tasto del mouse L’ispettore si posiziona in questa modalità

Page 82: Lezioni Cocoa

A questo punto faccio un clic sul OUTLET che voglio collegare all’oggetto che ho precedentemente selezionato e premo CONNECT.

Quando è collegato, compare un pallino sulla sinistra, e nella colonna Destination compare l’oggetto NSTextField. Rifaccio l’operazione di collegamento anche per il secondo campo a fianco del testo char min (che sara’ collegato all’outlet limiteCharMin)

Page 83: Lezioni Cocoa

Se diamo uno sguardo al nostro oggetto ilControllore nella videata MainMenu.nib ora non ha piu’ il punto esclamativo.

Siamo quasi al dunque,… abbiate fede… Ora non ci rimane che chiedere a Interface Builder di creare per noi i files di sorgenti relativi al nostro oggetto ilControllore che abbiamo creato. Perche’ questo ? Semplice, noi vogliamo scrivere dei valori nei due NSTextField che abbiamo posizionato nella finestra metallizata e tali valori devono essere scritti dal nostro programma, quindi abbiamo bisogno dei files di programma (.m e .h) che rappresentano l’oggetto ilControllore. Tali files devono essere inclusi nel nostro progetto di xcode. Per far creare a Interface Builder i files necessari, selezioniamo CLASSES dalla finestra MainMenu.nib

Page 84: Lezioni Cocoa

Quindi selezioniamo il nostro oggetto ilControllore e facciamo comparire il menu contestuale (clic tasto destro del mouse)

Page 85: Lezioni Cocoa

Questa volta scegliamo CREATE FILES FOR ilControllore e compare

vedete che ha gia’ assegnato i nomi ai files .m e .h cre saranno creati e che saranno automaticamente aggiunti al progetto “limiti”. Non dobbiamo far altro che premere CHOOSE.

Bene, è giunto il momento di abbandonare Interface Builder, salviamo tutto e chiudiamo.

Page 86: Lezioni Cocoa

Ritorno si XCODE e mi ritrovo i files che sono stati aggiunti da Interface Builder

Page 87: Lezioni Cocoa

Bene, vediamo cosa c’e’ scritto dentro i files ilControllore.h e ilControllore.m, che sono parte dei sorgenti del nostro programma. Per vederne il contenuto, ciccate sul pulsante Editor nella barra strumenti

in modo da avere la seguente modalità di visualizzazione

Page 88: Lezioni Cocoa

Quello che vediamo è stato scritto in automatico (seguendo le nostre indicazioni…) relativamente all’oggetto ilControllore. Sono facilmente riconoscibili i due outlet che abbiamo in precedenza creato.

Il file ilControllore.m, invece non ha nessuna indicazione particolare. Per concludere il mio tutorial, volevo scrivere il valore max e minimo consentito per un tipo di dato char. Per fare questo, devo intercettare un particolare evento di Cocoa, che si chiama awakeFromNib.

Page 89: Lezioni Cocoa

In pratica, quando lancio il programma, il programma in automatico carichera’ in memoria il file NIB indicato e creera’ tutti gli oggetti presenti nel file NIB stesso (tra cui il nostro ilControllore). Quando questo avviene, l’applicazione avvisa tutti gli oggetti inviando loro un messaggio di tipo awakeFromNib appunto. (=risvegliato dal NIB) In questo modo, nel mio programma, io posso effettuare delle azioni non appena l’oggetto viene creato, nel caso specifico l’azione che io voglio fare è quella di scrivere un valore dentro l’oggetto NSTextField collegato all’outlet limiteCharMax. Per fare cio’ devo aggiunger il metodo awakeFromNib nel codice sorgente del mio oggetto ilControllore.c e quindi all’interno di tale metodo, ricavare il valore max e min consentiti per un char. Per ricavare tale valore, non faccio altro che usare i valori costanti definiti dal file limits.h (che potete cercare sul vostro Mac.) Questo è un pezzo di tale file #include <ppc/_limits.h> #define CHAR_BIT 8 /* number of bits in a char */ #define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */ #ifndef CLK_TCK #define CLK_TCK __DARWIN_CLK_TCK /* ticks per second */ #endif /* * According to ANSI (section 2.2.4.2), the values below must be usable by * #if preprocessing directives. Additionally, the expression must have the * same type as would an expression that is an object of the corresponding * type converted according to the integral promotions. The subtraction for * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values * are written as hex so that GCC will be quiet about large integer constants. */ #define SCHAR_MAX 127 /* min value for a signed char */ #define SCHAR_MIN (-128) /* max value for a signed char */ #define UCHAR_MAX 255 /* max value for an unsigned char */ #define CHAR_MAX 127 /* max value for a char */

Page 90: Lezioni Cocoa

#define CHAR_MIN (-128) /* min value for a char */ #define USHRT_MAX 65535 /* max value for an unsigned short */ #define SHRT_MAX 32767 /* max value for a short */ #define SHRT_MIN (-32768) /* min value for a short */ …. Quindi il valore massimo di un char è indicato dalla COSTANTE CHAR_MAX che vale 127 come visibile dal file. Dato che il valore è numerico, ed il campo che io ho messo nella finestra metallizzata è un NSTextField (campo di testo) lo devo convertire in testo. Per fare tale operazione, uso un oggetto Cocoa che rappresenta una stringa di caratteri NSString ed uso un suo metodo per convertire numeri in testo stringWithFormat Vedremo comunque meglio ed in dettaglio queste cose, in una prossima lezione. In pratica il codice che vado ad inserire dentro ilControllore.m Tra @implementation e @end è

Quindi effettuo le operazioni di conversione dati numerici in stringa

e dico alla mia outlet (che rappresenta il campo NSTextField char max) di che ora contiene una stringa che è il dato che interessa.

Page 91: Lezioni Cocoa

Ecco come si presenta il codice completo di ilControllore.m #import "ilControllore.h" @implementation ilControllore -(void) awakeFromNib{ NSString *unaStringa; unaStringa=[NSString stringWithFormat:@"%d", CHAR_MAX]; [limiteCharMax setStringValue:unaStringa]; unaStringa=[NSString stringWithFormat:@"%d", CHAR_MIN]; [limiteCharMin setStringValue:unaStringa]; } @end Ed ecco il risultato finale dell’applicazione e del tutorial.

Esercitatevi a fare tutti i passagi che ho descritto in modo da acquisire la necessaria manualità ed a familiarizzare con l’ambiente XCODE e Interface Builder. Per i piu’ intraprendenti: provare a completare l’applicazione facendo calcolare anche gli altri valori e rendendo i campi solo di OUTPUT.

Page 92: Lezioni Cocoa

Se volete potete anche inviarmi il vostro lavoro al termine, al mio indirizzo email. Francesco Germinara [email protected] www.germinara.it

Page 93: Lezioni Cocoa

Il programmatore che c'è in noi - Lezione 4 – Variabili Le variabili, in un programma, sono i “contenitori” dentro cui memorizzare dei valori, che possono cambiare (per questo si chiamano variabili) durante l’esecuzione del programma stesso. Quindi per semplificare il concetto di variabile, immaginiamo di avere delle scatole (come avevamo già fatto parlando dei tipi di dati), ma questa volta diamo un nome alle scatore, in modo da poterle facilmente individuare. Le azioni che posso fare, usando queste scatole, sono sostanzialmente di “vedere” cosa contiene una scatola oppure “mettere” qualcosa nella nostra scatola. Ovviamente, riferendomi alle lezioni sui tipi di dato, una scatola è “personalizzata” in base al tipo di dato che essa conterrà. La sintassi (ossia il modo in cui devo scrivere un istruzione in un linguaggio di programmazione) per poter dichiarare una variabile in linguaggio C / C++ e ObjectiveC e’ la seguente Tipo di dato Nome della

variabile Valore iniziale

Vediamo degli esempi: Se nel mio programma dovro’ gestire dei dati di tipo intero esempio l’eta’ di due persone (mio padre e mia madre) avro’ la necessità di usare due VARIABILI (ossia due scatole, dentro cui mettere i valori relativi agli anni dei miei genitori). Per dichiarare (ossia, creare, far nascere, all’interno del programma una variabile) mi pongo alcune semplici domande:

1) che tipo di dato deve contenere la variabile ? La risposta a tale domanda, determina il TIPO DI DATO da usare nella sintassi per la dichiarazione della variabile stessa

2) quale e’ l’informazioni che sara’ gestita dalla variabile ? La risposta a tale domanda, mi aiuta a scegliere il NOME DELLA VARIABILE.

Page 94: Lezioni Cocoa

3) ha un valore iniziale ? In questo caso, la mia risposta è sempre SI, il valore iniziale io lo metto sempre, anche se vale 0.

Nel esempio, il tipo di dato che deve contenere l’eta’, potrebbe essere un int, un unsigned short, un char o un double. Ovviamente, la scelta migliore deve essere fatta tenendo in considerazione, quando possibile, l’ottimizzazione dell’utilizzo della memoria RAM del nostro Mac. Scelgo, unsigned char Per il nome, decido nAnniPapa e nAnniMamma NOTA: Non esiste un criterio universalmente riconosciuto per scrivere il nome della variabile. Come regole di base, non usate simboli di punteggiatura, non scrivete tutto in maiuscolo, non iniziate un nome di variabile con un numero, non lasciate spazi tra le parti componenti il nome. Comunque, se il nome che avete scelto non e’ accettabile dal “compilatore” (=programma che elabora le nostre istruzioni di programma scritte in un certo linguaggio di programmazione, e le trasforma in istruzioni per il microprocessore del nostro Mac) sara’ segnalato un errore nel momento in cui cercherete di mandare in esecuzione il programma (per come fare a compilare e mandare in esecuzione un vostro programma, scaricate il tutorial su XCODE della puntata precedente). Cercate sempre di usare un nome di variabile che sia il piu’ descrittivo possibile (evitando di scrivere un poema…) questo è di FONDAMENTALE importanza, perche’ quando rimettete le mani su un vostro programma a distanza di tempo, sarete in grado di risalire alle funzionalita’ del programma ed allo scopo delle variabili. La stessa cosa vale se dovrete mettere le mani su programmi fatti da altri e viceversa. Vediamo quindi come scriveremo nel nostro programma le due variabili di cui abbiamo parlato Tipo Dato Nome variabile Valore Iniziale unsigned char nAnniPapa 0 unsigned char nAnniMamma 0

Page 95: Lezioni Cocoa

ASSEGNAZIONE DI UN VALORE AD UNA VARIABILE Per mettere qualcosa nella scatola si usa l’operatore di assegnazione indicato dal simbolo = Quindi per assegnare un valore ad una variabile si usa l’operatore = unsigned char nAnniPapa=45; //dichiaro la variabile e gli assegno un valore unsigned char nAnniMamma=38; //dichiaro la variabile e gli assegno un valore Esaminiamo questa riga di codice unsigned char nAnniPapa=45; //dichiaro la variabile e gli assegno un valore Va letta nel modo seguente “assegnamo il valore numerico intero pari a 45 alla variabile di tipo unsigned char che si chiama nAnniPapa” E scomponiamola nei vari elementi. unsigned char indica il tipo di dato della nostra variabile nAnniPapa indica il nome della nostra variabile = indica l’operazione di assegnamento di un valore ad una variabile 45 indica il valore che intendo assegnare alla variabile ; indica la fine di una istruzione in linguaggio C/C++/ObjectiveC // indica l’inizio di un commento. Da questo punto in poi tutto quello che e’ scritto sulla riga e’ da considerarsi un commento

Page 96: Lezioni Cocoa

Nella definizione iniziale di variabile ho detto che il valore di una variabile puo’ cambiare durante l’esecuzione di un programma, semplicemente basta assegnare ogni volta che si vuole un nuovo valore usando l’operatore = (assegnazione). Esempio //Dichiarazione delle variabili unsigned char nAnniPapa=45; //Anni Papa’ unsigned char nAnniMamma=38; //Anni Mamma //Ora voglio assegnare nuovi valori nAnniPapa = 52; //Assegno il valore 52 alla variabile nAnniPapa nAnniMamma = 45; Posso anche assegnare il valore di una variabile ad un'altra In questo modo //Supponiamo che papa’ e mamma abbiano la stessa eta’ nAnniPapa= nAnniMamma; Posso assegnare il risultato di un calcolo nAnniPapa = 2006 – 1966; oppure nAnniPapa = nAnniMamma+5; Per i piu’ curiosi… Tecnicamente parlando, la variabile che si trova alla SINISTRA del simbolo = (assegnazione) si chiama LVALUE, ricordatevi questo nome, in alcuni casi il compilatore vi potrebbe segnalare questo errore: invalid lvalue in assignment , che significa appunto che c’e’ un errore nella parte sinistra di un operatore di assegnazione, l’operazione non puo’ essere fatta. Esempio di tale errore 7=5; //7 Non e’ un lvalue e’ un valore costante e quindi non puo’ essere modificato Vi lascio sperimentare la dichiarazione delle variabili all’interno di XCODE, ho preparato a tal proposito questo semplice progetto. Esempi di dichiarazioni e di assegnazione di variabili

Page 97: Lezioni Cocoa

double nTotCostoCassetta=0.0; int nNumeroDiMele=0; double nCostoMela=1.5; //Assegnazione dati nNumeroDiMele=100; //Calcolo costo totale e assegno il risultato alla variabile nTotCostoCassetta = nNumeroDiMele * nCostoMela; Saluti.

Page 98: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 5 – Introduzione ai Puntatori Le variabili sono estremamente importanti nella programmazione, indipendentemente dal linguaggio di programmazione che si intende utilizzare. La loro comprensione e’ di conseguenza di fondamentale importanza, quindi oggi approfondiamo il discorso relativo alle variabili iniziato in precedenza. Quando noi dichiariamo una variabile di un certo tipo di dato, non facciamo altro che “dire” (tramite l’istruzione di programma) al compilatore, “mi riservi una certa quantita’ di memoria RAM del computer” La quantita’ di memoria che ci viene “riservata” dipende dal tipo di dato che la variabile stessa dovra’ contenere e di conseguenza dal suo tipo dato specificato nella sua dichiarazione. Tanto per capirci, se io dichiaro una variabile di tipo int il compilatore mi assegnera’ 4 bytes di memoria Ram (questo lo possiamo verificare con l’utilizzo dell’operatore sizeof() come avevamo fatto in una delle prime lezioni). Esempio int nNumeroRivista=0; //Dichiaro la variabile di tipo int e la inizializzo a 0 int nBytesOccupati=0; //Calcolo lo spazio di memoria occupato dalla variabile nNumeroRivista nBytesOccupati = sizeof(nNumeroRivista); // 4 bytes Ma dove sono dislocati questi quattro bytes nella nostra memoria RAM ? O per dirlo in termine informatico, quale e’ l’indirizzo nella nostra memoria RAM della variabile ? Il programma, quando sara’ eseguito riservera’ lo spazio di memoria richiesto, come indicato dalla nostra istruzione ma lo riservera’ in una zona di memoria RAM libera e a sua completa discrezione, di conseguenza solo quando il programma sara’ in esecuzione saremo in grado si conoscere la locazione di memoria (indirizzo) dove iniziano i BYTES che ci sono stati riservati. Inoltre ad ogni riavvio del programma le locazioni dei nostri BYTES saranno quasi sicuramente cambiate. La cosa certa e’ che i BYTES saranno CONSECUTIVI. Prima di rispondere a tale domanda, realizziamo un semplice (spero) schema per riepilogare la situazione. Supponiamo che la nostra memoria RAM si presenti tutta libera ed in questa forma… Indirizzo Byte 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 … 512MB --------------------------------------------------------------- | | | | | | | | | | | | | | | | --------------------------------------------------------------- Dopo l’esecuzione del programma, quando viene eseguita la nostra istruzione int nNumeroRivista=0 la situazione cambia e supponiamo sia diventata questa

Page 99: Lezioni Cocoa

Indirizzo Byte 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 … 512MB --------------------------------------------------------------- | | | | | | | | | | | 0 | 0 | 0 | 0 | | --------------------------------------------------------------- nNumeroRivista come detto in precedenza, non siamo in grado di prevedere dove si troveranno le locazioni di memoria occupate dai nostri 4 BYTES Quindi, in questo caso, la risposta alla domanda precedente e’: la variabile nNumeroRivista e’ stata posizionata (=allocata) alla locazione di memoria con indirizzo di partenza pari a 10. Quindi i nostri 4 BYTES saranno rispettivamente agli indirizzi 10,11,12,13. Bene, in C/C++ e ObjectiveC esiste un OPERATORE che ci consente di conoscere la locazione di partenza di una qualsiasi variabile, ossia di conoscerne il suo INDIRIZZO in MEMORIA RAM. Tale operatore e’ & (and) Quindi per sapere realmente la locazione di memoria a cui e stata “posizionata” la nostra variabile devo scrivere una istruzione di questo tipo indirizzoVariabile = &nomeVariabile e quindi nel nostro esempio indirizzoVariabile = &nNumeroRivista; //Ricavo l’indirizzo (di partenza) della variabile Spero che sino a qui, tutto sia sufficientemente chiaro… Se volete fare una pausa, e prendere un caffe’, questo e’ il momento… Le cose, si complicano…

1) Complicazione Tutti gli indirizzi di memoria del computer sono indicati con un valore ESADECIMALE (HEX) Noi normalmente siamo abituati a usare i numeri con base DECIMALE, ossia, contiamo da 0 a 9 e quando arriviamo a 10, incrementiamo le decine e ripartiamo con le unita’ 0 a 9 ecc. si dice che la base e’ 10 (decimale appunto). Quando invece si conta in esadecimale (indicato con Hex, h o 0X o 0x) la base e’ 16 e quindi si conta da 0 a F (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F) . Le seguenti due istruzioni sono uguali nNumeroRivista=223; //Assegno il valore DECIMALE nNumeroRivista=0xDF; //Assegno il valore Hex Per la conversione dei valori Dec/Hex e viceversa, vi consiglio di usare l’applicazione Calcolatrice del vostro Mac. Per chi vuole approfondire il discorso, consiglio di fare delle ricerche in Internet o se qualcuno ha tempo/voglia potrebbe approfondire meglio il discorso qui su Tevac.

Page 100: Lezioni Cocoa

2) Complicazione Il valore che viene calcolato dall’operatore &, e’ di un TIPO DI DATO particolare, molto particolare, e’ un PUNTATORE. Quindi sembra un valore int ma non lo e’. Di conseguenza NON posso fare una operazione di questo tipo

int nNumeroRivista=0; //Dichiaro la variabile di tipo int e la inizializzo a 0 int indirizzoVariabile=0; indirizzoVariabile=& nNumeroRivista; //Calcolo l’indirizzo della variabile

Questa riga viene compilata con un Warning del compilatore che recita pressappoco cosi’ “warning: assignment makes integer from pointer without a cast”

Per memorizzare un INDIRIZZO devo avere una variabile di TIPO PUNTATORE ad TIPO DI DATO DELLA VARIABILE DELLA QUALE MI INTERESSA L’INDIRIZZO. Come faccio a dichiarare la variabile puntatore che mi serve ? 1) penso ad un nome coerente con la variabile a cui si riferisce l’indirizzo esempio, la variabile della quale voglio conoscere l’indirizzo si chiama nNumeroRivista, il nome della mia variabile di tipo puntatore che dovra’ contenere l’indirizzo della variabile nNumeroRivista la chiamo pNumeroRivista (la p che ho usato come prefisso mi “ricorda” che e’ un puntatore 2) di che tipo e’ la variabile della quale voglio calcolare l’indirizzo ?

nNumeroRivista e’ di tipo int, di conseguenza il mio puntatore e’ un puntatore ad un tipo int

3) come indico nel programma che la variabile e’ una variabile puntatore ? Si usa un ulteriore OPERATORE del linguaggio di programmazione, che e’ * (asterisco) da anteporre al nome della variabile (*nomevariabile) o da attaccare all’identificatore di tipo (int*) il risultato e’ lo stesso. La scelta di un modo piuttosto che l’altro e’ una questione stilistica e (reputo) personale. NOTA Quando io dichiaro una variabile di tipo int, ad esempio, la inizializzo al valore 0 (zero). Quando la variabile e’ di tipo puntatore a quale indirizzo la inizializzo quando la dichiaro ? La risposta e’ a NULLA, a NIENTE, a nessun indirizzo. Per indicare questa condizione, in C e C++ si usa la parola chiave null mentre in ObjectiveC si usa nil.

Bene, ci siamo… riprendiamo il nostro esempio int nNumeroRivista=0; //Dichiaro la variabile di tipo int e la inizializzo a 0 int* pNumeroRivista=nil; //Dichiaro la variabile di tipo puntatore ad un int e la inizializzo a nil //Calcolo l’indirizzo della variabile

Page 101: Lezioni Cocoa

pNumeroRivista=& nNumeroRivista; //calcolo il valore dell’indirizzo e lo memorizzo nella variabile pNumeroRivista. Il valore di indirizzo potrebbe essere, ad esempio, 0xbffff614 Per vedere il valore di indirizzo del puntatore, se usiamo la NSLog() gia’ incontrata in altre occasioni, dovremo scrivere in questo modo NSLog(@"Indirizzo di nNumeroRivista: %p",pNumeroRivista); Da notare l’uso del simbolo %p per convertire il dato da puntatore (indirizzo) a stringa (caratteri). In allegato trovate un programma di esempio con quanto trattato in questa parte e qualcosetta in piu’ che sara’ trattato prossimamente. Questo e’ il Run log prodotto dal programma … LeVariabiliApprofondimento[1085] Valore contenuto in nNumeroRivista: 223 LeVariabiliApprofondimento[1085] Dimensione Occupata da nNumeroRivista: 4 LeVariabiliApprofondimento[1085] Indirizzo di nNumeroRivista: 0xbffff628 LeVariabiliApprofondimento[1085] All' Indirizzo 0xbffff628 c'e' il valore 223 LeVariabiliApprofondimento[1085] Ora all' Indirizzo 0xbffff628 c'e' il valore 548 LeVariabiliApprofondimento[1085] ed ovviamnete anche nNumeroRivista vale 548 Per i piu’ intraprendenti… nella finestra dell’applicazione e’ contemplata anche la conversione del valore della variabile in valore binario, ma non e’ ancora implemenata … chi vuole puo’ farlo e postare la propria soluzione. Saluti e buone feste.

Page 102: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 6 – Aritmetica e Puntatori La volta scorsa abbiamo dato la definizione di una variabile puntatore, di seguito riassunta “Un puntatore e’ una variabile che contiene l’indirizzo di una locazione di memoria” Vi arriva una busta chiusa, l’aprite, e trovate un bigliettino con un messaggio del tipo “presentati in via Verdi,n.8” Andate in “via Verdi,n.8” e ci trovate una villa bifamiliare. Bene, cosa significa ? Semplice, la busta e’ una variabile di tipo puntatore, infatti contiene l’indirizzo di un altro oggetto (la villa bifamiliare) non l’oggetto stesso (ci vorrebbe una busta enorme…) Si dice quindi che la variabile PUNTA all’oggetto indicato dall’indirizzo. Se nella stessa busta, sostituisco il bigliettino, con un altro su cui c’e’ scritto “presentati in via Rossi n.25”, significa che ho cambiato il valore alla mia variabile di tipo puntatore (ossia ho cambiato l’indirizzo dell’oggetto a cui essa punta). Supponiamo ora che io vi consegni la busta e vi dica anche, andare alla villa successiva a quella indicata nella busta. Come vi comportate ? La situazione di via Verdi e’ questa: via Verdi 8 – Prima Villa bifamiliare (prima villa) via Verdi 9 – Prima Villa bifamiliare (seconda villa) via Verdi 10 – Seconda Villa bifamiliare (prima villa) via Verdi 11 – Seconda Villa bifamiliare (seconda villa) Andate alla villa al N° 9 o quella al N° 10 ? Dipende. Dipende dal tipo di oggetto a cui punta il puntatore, quindi se l’indirizzo indicato nella nostra busta e’ relativo ad una villa bifamiliare, quando dico di andare all’indirizzo successivo, andro alla successiva villa bifamiliare, quindi alla N. 10 di via Verdi. Se invece, l’indirizzo indicato nella busta, e’ relativo (=punta) ad una villa singola, allora la villa successiva e’ quella al N° 9 di via Verdi. Questo e’ esattamente quello che avviene quando noi effettuiamo delle operazioni aritmetiche con i puntatori. Per concludere quella similitudine, tra puntatori e buste con indirizzi… vi segnalo un ulteriore interessante particolare, la busta stessa e’ un oggetto; di conseguenza potrei avere una ulteriore busta (variabile puntatore) che contiene l’indirizzo dove trovare una busta che contiene a sua volta l’indirizzo della villa. In effetti posso avere un puntatore che punta ad un puntatore che punta ad un puntatore … ecc.

Page 103: Lezioni Cocoa

Abbiamo gia’ incontrato dei particolari caratteri che hanno uno specifico significato proprio per consentire di lavorare con le variabili di tipo puntatore. & Serve per ricavare l’indirizzo di memoria di un oggetto * Serve per dichiarare una variabile di tipo puntatore Lo stesso simbolo * si usa per l’operatore che e’ complementare al quello & e serve per ottenere il valore contenuto nell’oggetto indicato dall’indirizzo specificato. Esempio: //dichiaro le variabili int nNumeroCivico=0; //variabile di tipo int int* pUnNumeroCivico=nil; //variabile puntatore ad un int int nUnAltroNumeroCivico=0; //variabile di tipo int nNumeroCivico=8; //Assegno il valore alla variabile int pUnNumeroCivico = & nNumeroCivico; //ricavo l’indirizzo di memoria della variabile ad un int nUnAltroNumeroCivico = *pUnNumeroCivico; //ricavo il valore della variabile che si trova //all’indirizzo contenuto in pUnNumeroCivico // ossia l’indirizzo di nNumeroCivico e di // conseguenza il suo valore e cioe’ 8. //a questo punto la variabile nUnAltroNumeroCivico vale 8. *pUnNumeroCivico = 12; //Cosa succede ? //Semplice, ho modificato il valore contenuto nella variabile puntata da pUnNumeroCivico ossia nNumeroCivico, quindi a questo punto nNumeroCivico vale 12. --------------------------------------------------------------------------------------------------------------------- OPERATORI ARITMETICI Gli operatori aritmerici sono dei particolari simboli che ci consentono di effettuare delle operazioni aritmetiche sui numeri. In linguaggio C/C++ e Objetive C gli operatori aritmetici sono - Sottrazione + Addizione * Moltiplicazione / Divisione % Modulo (resto di una divisione tra numeri interi) -- Decremento ++ Incremento Esempi int nAnnoNascita=1966; int nAnnoCorrente=2006; int nEta=0; nEta= nAnnoCorrente – nAnnoNascita; //Uso operatore – per effettuare il calcolo e l’operatore = per assegnare il risultato (40) alla variabile nEta

Page 104: Lezioni Cocoa

int nNumero=45; BOOL bIsDispari=FALSE; bIsDispari = numero % 2; //Uso operatore modulo %, per sapere se un numero e’ dispari o meno, l’operatore modulo restituisce il resto della divisione tra interi, quindi se il numero e’ pari il resto della divisione per 2 vale 0 altrimenti vale 1. int nContatore=0; nContatore++; //uso l’operatore di incremento per incrementare di 1 il valore della variabile // nContatore a questo punto vale 1 nContatore++; // nContatore a questo punto vale 2 nContatore--; //uso l’operatore di decremento per decrementare di 1 il valore della variabile // nContatore a questo punto vale 1 NOTE In C/C++ e Objetive C posso usare anche gli operatori “composti” ossia operatore di assegnazione e operatore aritmetico Esempio: nContatore+=5; //uso l’operatore composto per assegnare a nContatore il valore di nContatore + 5 nContatore-=3; //uso l’operatore composto per assegnare a nContatore il valore di nContatore - 3 nContatore*=3; //uso l’operatore composto per assegnare a nContatore il valore di nContatore * 3 nContatore/=3; //uso l’operatore composto per assegnare a nContatore il valore di nContatore / 3 Gli operatori di incremento e decremento possono essere posto davanti (prefisso) o dietro (postfisso) la variabile, la differenza e’ nella valutazione della valore della variabile. Nel caso in cui siano posti davanti, prima si applica l’operatore (ossia si incrementa o decrementa il valore) e poi si valuta il valore della variabile, nel caso opposto, prima viene valutato il valore della variabile e poi si procede ad applicare l’operatore. Esempio: int nContatore=0; int nValore=0; //Se scrivo nValore =++nContatore; // nValore = Vale 1, nContatore Vale 1 (prima viene incrementato il valore di nContatore da 0 a 1, quindi il valore viene assegnato alla variabile nValore) //Se invece scrivo

Page 105: Lezioni Cocoa

nValore =nContatore++; // nValore = Vale 0, nContatore Vale 1 (prima viene assegnato il valore di nContatore (0) alla variabile nValore, quindi viene incrementato il valore di nContatore da 0 a 1) Gli operatori possono essere unary,binary o ternary a seconda se hanno bisogno di un solo operando, di due o di tre. Gli operatori aritmetici unary sono – (cambio segno) ++ (incremento) -- (decremento) mentre gli altri sono binary. Per concludere il discorso sugli operatori arimetici, occorre dire che esiste una PRECEDENZA tra operatori, ossia, se in una espressione sono presenti piu’ operatori, essi vengono valutati in base alla loro precedenza. E’ possibile (anzi, vivamente consigliato…) utilizzare le parentesi tonde () per MODIFICARE la precedenza degli operatori o per meglio chiarire le intenzioni che abbiamo per la valutazione dell’espressione. PRECEDENZA DEGLI OPERATORI ARITMETICI Alta ++ -- - (unary cambio segno) * / % + - Bassa Gli operatori allo stesso livello sono valutati dal compilatore partendo da sinistra verso destra. Esempi: int nValore=0; int nPrimoNumero=5; int nSecondoNumero=2; int nTerzoNumero=4; nValore = nPrimoNumero * ++nSecondoNumero – nTerzoNumero; // Quanto vale ? //prima viene valutato l’operatore ++ che ha precedenza piu’ alta, quindi ++nSecondoNumero = 3 //quindi viene valutato l’operatore * di moltiplicazione nPrimoNumero * 3 = 5*3=15 //Infine viene valutato l’operatore – di sottrazione 15 – nTerzoNumero= 15 – 4 = 11 //Il risultato dell’espressione e’ quindi 11 //La seguente espressione fornisce come risultato -5 nValore = nPrimoNumero * (++nSecondoNumero – nTerzoNumero); // Quanto vale ? //Dato che ci sono le parentesi, la precedenza e’ modificata e quindi viene valutata in questo modo //Prima viene incrementato il valore di nSecondoNumero (da 2 a 3) //Poi ad esso viene sottratto il valore di nTerzoNumero (4) quindi 3 – 4 = -1 //Infine viene valutata l’espressione nPrimoNumero * -1 = 5 * -1 = -5 Per i piu’ intraprendenti … nValore = nPrimoNumero * nSecondoNumero++ – nTerzoNumero; // Quanto vale ? //In questo caso, la valutazione dell’espressione da come risultato 6 come mai ?

Page 106: Lezioni Cocoa

Ovviamente il mio personale consiglio e’ quello di scrivere sempre il codice (=il programma, il sorgente) nella maniera piu’ chiara possibile (=leggibile) Quindi, l’espressione che ho usato negli esempi precedenti, dovrebbe essere scritta in un modo piu’ leggibile, simile a questo int nValore=0; int nPrimoNumero=5; int nSecondoNumero=2; int nTerzoNumero=4; ++nSecondoNumero; nValore = (nPrimoNumero * nSecondoNumero) – nTerzoNumero; // Quanto vale ? Bene, siamo ora in grado di parlare della Aritmetica dei Puntatori, come indicato nel titolo di questa lezione… Supponiamo di avere questa situazione int nEta=10,nOldEta=0; //Dichiarazione multipla di variabili dello stesso tipo NOTARE l’utilizzo del simbolo , (virgola) e’ un altro operatore del linguaggio C/C++ e ObjectiveC, che serve per separare una lista di istruzioni int* pIndirizzoDiEta=nil; //dichiaro la variabile puntatore e la inizializza a nil (nulla) pIndirizzoDiEta = &nEta; //Calcolo l’indirizzo di memoria della variabile nEta e lo memorizzo //nella variabile puntatore nOldEta=*pIndirizzoDiEta; //Ricavo il valore della variabile puntata dal puntatore e lo memorizzo //in nOldEta, questa istruzione equivale a scrivere nOldEta = nEta; pIndirizzoDiEta++; //Incremento il valore di pIndirizzoDiEta, CHE E’ UN indirizzo di memoria //Di quanto e’ stato incrementato ? //A cosa punta il nuovo indirizzo ? Per rispondere a queste domande, facciamoci dire quanto vale l’indirizzo contenuto in pIndirizzoDiEta prima e dopo l’incremento usando NSLog(@"Indirizzo contenuto pIndirizzoDiEta=%p",pIndirizzoDiEta); Questo e’ il risultato relativo all’esecuzione sul mio mac, pIndirizzoDiEta=0xbffffa18 (prima) pIndirizzoDiEta=0xbffffa1c (dopo) Se ora uso l’applicazione calcolatrice, e effettuo la sottrazione tra i due valori (sono esadecimali) ottengo 0x4 ossia 4 in decimale. QUATTRO ? Il valore del contenuto nella mia variabile puntatore si e’ incrementata di un colpo solo di 4 non di 1 come probabilmente pensavamo. Vi ricordate l’esempio fatto qualche riga piu’ in alto delle villette bifamiliari, bene, con l’istruzione ++ abbiamo detto alla nostra variabile puntatore di puntare all’indirizzo successivo ad una variabile di tipo INT (dato che le variabili INT occupano 4 bytes in memoria, lo avevamo gia’ verificato con l’uso dell’operatore sizeof() ricordate?) e’ quindi corretto che il valore dell’indirizzo si sia

Page 107: Lezioni Cocoa

incrementato di 4 bytes. Ecco perche’ e’ importante sapere a che tipo di variabile punta una variabile puntatore. Se invece dell’istruzione pIndirizzoDiEta++; scrivo pIndirizzoDiEta+=4; //Il nuovo indirizzo sara’ 4 locazioni successive all’indirizzo di partenza //Dato che pIndirizzoDiEta e’ un puntatore che punta ad un int e che un int occupa 4 bytes in //memoria, con l’istruzione precedente mi sono spostato di 4 * 4 bytes = 16 Bytes. Se invece dichiaro un puntatore ad un char, dato che un char occupa un solo byte, mi sarei spostato di 4 bytes e non di 16. Esempio int nEta=10; char *pIndirizzoUnByte=nil; //Variabile puntatore a char int* pIndirizzoDiEta=nil; //Variabile puntatore a int pIndirizzoDiEta=&nEta; //Calcolo indirizzo e lo metto in pIndirizzoDiEta pIndirizzoUnByte = pIndirizzoDiEta; //Assegno il valore di pIndirizzoDiEta anche a //pIndirizzoUnByte (vedi nota) pIndirizzoDiEta++; //Indirizzo ora e’ stato incrementato di 4 (un int vale 4 bytes) pIndirizzoUnByte ++; //Indirizzo ora e’ stato incrementato di 1 (un char vale 1 byte) NOTA L’istruzione pIndirizzoUnByte = pIndirizzoDiEta; genera un warning del compilatore, in quanto si stanno assegnando dati di tipi diversi (un valore di puntatore ad interi viene assegnato ad un puntatore a char). E’ comunque una operazione lecita, per evitare la segnalazione occorre utilizzare un “CAST” di tipo, ossia una operazione di tipo di dato (nel nostro caso da tipo puntatore ad intero a puntatore a char). L’istruzione nella forma corretta e’ quindi pIndirizzoUnByte = (char*) pIndirizzoDiEta; //uso del cast (char*) per convertire il tipo di dato Se invece di incrementare l’indirizzo di una variabile puntatore, volessi incrementare il contenuto della variabile a cui punta l’indirizzo si procede nel seguente modo (*pIndirizzoDiEta)++; //Incremento il valore puntato dall’indirizzo contenuto in pIndirizzoDiEta (*pIndirizzoDiEta) += 4; //Sommo 4 al valore puntato dall’indirizzo contenuto in pIndirizzoDiEta NOTA Occorre usare le parentesi, altrimenti causa precedenza degli operatori, invece di incrementare il valore puntato dall’indirizzo incremento l’indirizzo stesso, come visto in precedenza. *pIndirizzoDiEta++; //Incrementa l’indirizzo e poi ricava il contenuto a cui punta il nuovo indirizzo

Page 108: Lezioni Cocoa

Concludo con un rapido riepilogo di quanto visto. int nEta=10; //Variabile di tipo int int nValore=0; //Variabile di tipo int int* pIndirizzoDiEta=nil; //dichiaro la variabile puntatore e la inizializza a nil (nulla) pIndirizzoDiEta = &nEta; //Calcolo l’indirizzo di memoria della variabile nEta e lo memorizzo //nella variabile puntatore (*pIndirizzoDiEta)++; // Incremento il valore della variabile puntata da pIndirizzoDiEta quindi // nEta, che passa da 10 a 11. (*pIndirizzoDiEta)+=5; // Incremento il valore della variabile puntata da pIndirizzoDiEta quindi // nEta, che passa da 11 a 16. (*pIndirizzoDiEta)=25; // Assegno il valore della variabile puntata da pIndirizzoDiEta quindi // nEta, che passa da 16 a 25. nValore = (*pIndirizzoDiEta); //Assegno a nValore il valore puntato da pIndirizzoDiEta //ossia nEta che attualmente vale 25 pIndirizzoDiEta++; //Incremento l’indirizzo di memoria contenuto in pIndirizzoDiEta che //passa ad esempio da 0xbffffbac a 0xbffffbb0 (+4Bytes) nValore = (*pIndirizzoDiEta); //Assegno a nValore il valore puntato da pIndirizzoDiEta // !!!! ATTENZIONE !!! Ora non punta piu’ a nEta, quindi non //siamo in grado di sapere a cosa punta e di conseguenza a quale e’ il //valore contenuto alla //locazione di memoria indicata (*pIndirizzoDiEta)=67; //!!! ATTENZIONE !!! Operazione MOLTO pericolosa, nel senso //che stiamo scrivendo in una zona di memoria di cui non conosciamo //il significato di conseguenza si rischia di “sporcare” //sino a rischiare il crash (=il blocco dell’applicazione, la chiusura // inaspettata…) //come l’esempio del log del crash della mia applicazione //quando ho cercato di eseguire queste istruzioni // pIndirizzoDiEta-=0xbffffbc4; // (*pIndirizzoDiEta)=789; Exception: EXC_BAD_ACCESS (0x0001) Codes: KERN_INVALID_ADDRESS (0x0001) at 0xc0000d78 Spero, di essere riuscito a essere chiaro ed esauriente in questa spiegazione. Le prossime lezioni, saranno di sicuro meno “pesanti”, la parte piu’ difficile ed ostica e’ proprio questa sui puntatori, quindi sforzatevi di comprenderne appieno il funzionamento, dopo di che’ tutto il resto e’ una passeggiata (o quasi…). Saluti, e a presto.

Page 109: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 7 – Arrays Quante volte avete aperto e chiuso un cassetto di una cassettiera ? Molte, credo. Bene, una cassettiera altro non e’ che un array di cassetti. Un array altro non e’ che un INSIEME DI ELEMENTI DELLO STESSO TIPO INDIVIDUATI DA UNO STESSO NOME. Per accedere ad un determinato elemento dell’array usiamo un indice. Nel esempio della nostra cassettiera, diro’ apri il primo cassetto, il secondo ecc. [1° cassetto] [2° cassetto] Gli arrays possono avere piu’ di una dimensione, di conseguenza, per accedere ad un determinato elemento si usano indici per ciascuna dimensione. Se la nostra cassettiera e’ formata da tre colonne di cassetti, disposti su due righe, in tutto avremo 3 x 2 cassetti = 6 cassetti. [1° cassetto] [2° cassetto] [3° cassetto] (prima riga) [1° cassetto] [2° cassetto] [3° cassetto] (seconda riga) Per accedere ad un determinato cassetto, dovro’ indicare il numero del cassetto ed in numero della riga, esempio apri il primo cassetto della prima riga, apri il secondo cassetto della seconda riga. Quindi possiamo avere arrays monodimensionali (una sola colonna o una sola riga), bidimensionali (una riga ed una colonna) e multidimensionali. Nella maggior parte delle applicazioni, ci troviamo a lavorare con arrays monodimensionali e bidimensionali Nel linguaggio di programmazione C/C++ e ObjectiveC l’indice del primo elemento e’ ZERO e tutti gli elementi dell’arrays occupano LOCAZIONI DI MEMORIA CONSECUTIVE nella Ram del nostro Mac. Il primo elemento corrisponde all’indirizzo di memoria piu’ basso, l’ultimo a quello piu’ alto. Per dichiarare una array di variabili si usa la seguente sintassi Singola dimensione TYPO_VARIABILE NOME_VARIABILE [NUMERO_ELEMENTI]; Due dimensioni TYPO_VARIABILE NOME_VARIABILE [NUMERO_RIGHE] [NUMERO_COLONNE];

Page 110: Lezioni Cocoa

Operazioni sugli arrays int nEtaPersone[50]; //Array di 50 elementi (accessibili usando indice tra 0 e 40 compresi) // di tipo INT char strCodice[12]; //Array di 12 char (caratteri) accessibili con indice 0-11 BOOL bBattagliaNavale[3][4];//Array bidimensionale di tre righe e quattro colonne di tipo BOOL Per assegnare il valore ad uno specifico elemento nEtaPersone[5]=37; //Assegna il valore 37 al 6° elemento dell’array … il primo elemento e’ 0… //Assegno dei caratteri all’array strCodice che e’ di tipo char strCodice=[0]=’C’; strCodice=[1]=’i’; strCodice=[2]=’a’; strCodice=[3]=’o’; bBattagliaNavale[0][0]=TRUE; //Assegno valore del primo elemento bBattagliaNavale[2][3]=TRUE; //Assegno valore dell’ultimo Per leggere il valore contenuto nell’array int nEta=0; nEta = nEtaPersone[5]; //nEta, vale 37 legge il valore del 6° elemento dell’array e lo assegna a nEta MOLTO IMPORTANTE 1) Prestate molta attenzione al valore degli indici degli array, il compilatore non e’ in grado di segnalare un uso errato del indice. Quindi se io ho un array di 50 caratteri, ed uso un indice che supera il valore di 49, il compilatore non mi segnala il problema, ma quando l’applicazione sara’ in esecuzione, potrebbe provocare dei malfunzionamenti all’applicazione stessa e farla chiudere in maniera inaspettata. 2) La sola dichiarazione delle variabili di tipo arrays non comporta la loro inizializzazione, quindi il valore in esso contenuto e’ sconosciuto. E’ sempre opportuno INIZIALIZZARE i valori degli arrary, semplicemente assegnando un valore ad ogni singolo elemento dell’array. L’inizializzazione puo’ essere fatta nella dichiarazione stessa o mediante uso dell’operatore di assegnazione (=) .

Page 111: Lezioni Cocoa

Esempio di inizializzazione di una array nello stesso momento della sua dichiarazione //Dichiaro un array di caratteri di 12 elementi, accessibili con indice tra //0 e 11 e lo inizializzo con la scritta Tevac Corso char strCodice[12]={'T','e','v','a','c',' ','C','o','r','s','o','.'}; Come visibile dall’esempio, per inizializzare i valori, devo usare l’operatore di assegnazione (=) quindi aprire un blocco usando il simbolo { specificare i singoli valori per ogni indice del nostro array, separandoli da una virgola ed infine chiudere il blocco con } Dato che si tratta di un array di char, i valori da usare per l’inizializzazione devono essere delle costanti di tipo char e si indicano con il valore di carattere racchiuso tra apici (non VIRGOLETTE, ma APICI, lo stesso simbolo dell’apostrofo) ‘T’ e’ una costante di tipo char (=di tipo carattere) int nCosti[3]={ 1200, 800, 899 }; //Inizializzo un array di dipo int double nQta={ 123.45, 234.56, 89.00 } //Inizializzo un array di tipo double Per inizializzare arrays bidimensionali, seguo la stessa regola, raggruppando ulteriormente ciascun gruppo di valori con un inizio e fine blocco ( { } ) per ciascuna riga. BOOL bBattagliaNavale[3][4]= { {0,0,0,0}, //inizializzo la prima riga {0,0,0,0}, //inizializzo la seconda riga {0,0,0,56} //inizializzo la terza riga }; Esempio di inizializzazione di una array con l’operatore di assegnazione E’ necessario assegnare singolarmente i valori ai vari elementi che compongono l’array. int nCosti[3]; //dichiaro l’array di interi ma non e’ inizializzato //inizializzo i valori dell’array nCosti[0]=1200; nCosti[1]=800; nCosti[2]=899; //Modico il valore di un elemento dell’array char strCodice[12]={'T','e','v','a','c',' ','C','o','r','s','o','.'}; strCodice[5]=’!’; //ora strCodice contiene Tevac!Corso ho sostituito il valore //del sesto elemento dell’array (era uno spazio) con il !

Page 112: Lezioni Cocoa

Uso dei puntatori con gli array Nelle lezioni precedendi abbiamo visto l’uso dei puntatori e della relativa aritmetica per accedere alle variabili. Dato che gli array di cui stiamo parlando sono collezioni di variabili dello stesso tipo, posso accedere ai dati di un array (quindi ai vari elementi) usando un puntatore invece che l’indice. //Dichiaro una variabile puntatore ad interi e la inizializzo a NULL int* pElemento=NULL; int nCosti[3]={ 1200, 800, 899 }; //Dichiaro ed inizializzo un array di dipo int di TRE elementi. //Calcolo l’indirizzo di memoria del primo elemento dell’array usando l’operatore & pElemento = & nCosti[0]; //Calcola l'indirizzo della variabile relativa al primo elemento dell'array (*pElemento)=45; //ASSEGNO IL VALORE 45 alla variabile puntata dal puntatore //pElemento (in questo caso e' il primo elemento dell'array) pElemento++; //Passo all'elemento successivo dell'array (indice 1) (*pElemento)=78; //Ora pElemento PUNTA al secondo elemento dell’array (indice = 1) E cosi via. Attenzione a non superare il numero di elementi precedentemente dichiarati nella’array. Concludo con un esempio pratico dell’uso di un array. Esempio: Vogliamo memorizzare le nostre uscite finanziarie nei diversi mesi dell’anno. Se non uso gli array, devo dichiarare 12 variabili per memorizzare il valore delle uscite per ciascun mese invece mi basta dichiarare un array di 12 elementi. int nSpeseNelMese[12]; //Spese per ciascun mese //Inizializzo l’array con le spese, mese per mese nSpeseNelMese[0]=120; //speso a Gennaio nSpeseNelMese[1]=170; //speso a Febbraio nSpeseNelMese[2]=190; //speso a Marzo nSpeseNelMese[3]=10; //speso a Aprile nSpeseNelMese[4]=140; //speso a Maggio nSpeseNelMese[5]=180; //speso a Giugno nSpeseNelMese[6]=190; //speso a Luglio nSpeseNelMese[7]=320; //speso a Agosto nSpeseNelMese[8]=520; //speso a Settembre nSpeseNelMese[9]=220; //speso a Ottobre nSpeseNelMese[10]=1120;//speso a Novembre nSpeseNelMese[11]=70; //speso a Dicembre Saluti.

Page 113: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 8– Array di caratteri, stringhe e costanti carattere Nel corso delle precedenti puntate abbiamo imparato (spero) a conoscere gli array sia di numeri che di caratteri. Nella creazione di programmi si ha spesso a che fare con del testo, il linguaggio C non ha un proprio tipo di dati per gestire il testo, ma usa gli array di caratteri terminati da uno speciale carattere chiamato NUL. (che vale 0 decimale 0x0 esadecimale ‘\0’ costante carattere) Tanto per essere chiari: char nome[10]; //Dichiara un array di 10 caratteri (indicizzabile tra 0 e 9) nome[0]=’F’; nome[1]=’r’; nome[2]=’a’; nome[3]=’n’; nome[4]=’c’; nome[5]=’o’; nome[6]=’\0’; Ora nome e’ una stringa cioe’ “Franco”. La prima implicazione e’ che quando io devo dichiarare la dimensione del mio array che dovra’ contenere una stringa DEVO aggiungere 1 alla dimensione che mi serve, in quanto devo considerare il carattere NUL che devo aggiungere per terminare la stringa. Nell’esempio indicato il testo massimo che potra’ contenere la stringa nome, e’ di 9 caratteri + 1 NUL (totale 10 singoli caratteri, come dichiarato all’inizio) L’istruzione nome[6]=’\0’; puo’ essere tranquillamente sostituita con nome[6]=0x0; //NUL valore esadecimale oppure nome[6]=0; //NUL valore decimale Fate attenzione a non scrivere nome[6]=’0’; //In questo caso assegno la cifra 0 e non NUL !!! Quindi nome non e’ stringa, ma SOLO un array di caratteri. Tutte le lettere e le cifre che utilizziamo, possono essere rappresentate da una costante di tipo carattere oppure dall’equivalente codice ASCII. Esempio: Il carattere A si indica con ‘A’ come costante carattere oppure come valore numerico 65 decimale in codice ASCII. Tra le costanti carattere segnalo quelle particolari, ossia codici che non hanno un equivalente nella nostra lingua ma hanno un significato speciale se usate nei programmi e che sono rappresentate dal fatto di avere il simbolo BACKSLASH \ seguito da un carattere il tutto racchiuso tra singoli apici. Tabelle delle costanti carattere con backslah Codice Significato ‘\b’ Backspace ‘\f’ Form feed ‘\n’ New line

Page 114: Lezioni Cocoa

‘\r’ Carriage return ‘\t’ Horizontal Tab ‘\”’ Double quote ‘\’’ Single Quote ‘\\’ Backslash ‘\xN’ Hexadecimal constant N ‘\N’ Octal constant N La costante NUL di cui abbiamo parlato in precedenza, quindi altro non e’ che ‘\0’ ossia zero il ottale (che vale comunque zero in decimale…) Un ultima considerazione, la costante ‘\n’ in realta’ e’ formata da due caratteri il carattere Carriage return (0xA) o 10 ed il carattere line feed (0xD) o 13, e generalmente indica la fine di una riga in un file di testo (a volte dipende dal sistema operativo...). Per mettere in pratica quanto esposto ho realizzato il programmino scaricabile qui Per gestire le stringhe in C language, si utilizzano delle funzioni di libreria, quali strcpy() per assegnare un valore, strcmp() per confrontare due stringhe e printf() per visualizzare il valore di una variabile di tipo stringa. Per informazioni sull’uso delle funzioni di manipolazione delle stringhe, e’ sufficiente cercare in internet, troverete innumerevoli esempi e spiegazioni. Dato che l’obiettivo e’ quello di programmare in Cocoa, vi anticipo che tramite Cocoa e quindi Objective C e’ comunque possibile gestire le stringhe come array di caratteri ed usare le funzioni standard di libreria, ma Cocoa ha una apposita CLASSE, di nome NSString e sue derivate, NSMutableString ecc. per gestire le stringhe, di conseguenza ne parleremo quando inizieremo a parlare di Cocoa. Saluti.

Page 115: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 9– Strutture, Unioni, Enumerazioni Tutti abbiamo un carta d’identita’. (la mia e’ scaduta, tra l’altro…) La nostra carta di identita’ contiene un insieme di dati di diverso tipo e di diverse dimensioni. Sono presenti dati quali Cognome (stringa o array di caratteri) Nome (stringa) Comune di Nascita (stringa) Data di nascita (immaginiamola divisa in tre interi, anno, mese, giorno) Altezza (double) ecc. La cosa veramente importante e’ che in un solo tipo di dato (la carta di identita’) sono state raggruppate diverse informazioni (dati) ma che sono in qualche modo “logicamente” collegate tra di loro. Pensate se invece di avere un unico documento con tutti i dati identificativi, avessimo un documento per ciascun dato (una carta che specifica il Nome, una il Cognome, una dove siamo Nati …) mentre e’ estremamente comodo gestire un solo documento che contenga tutte le informazioni necessarie per l’identificazione di una persona. Bene, la carta di identita’ e’ una STRUTTURA DATI. Una struttura e’ una collezione di variabili, anche di tipo e dimensioni differenti, che possono essere gestite tramite un solo nome. In modo da garantire un modo semplice ed immediato il legame logico che i dati, presenti nelle singole variabili, hanno tra di loro e per semplificarne la gestione. Per definire una struttura dati, si utilizza la keyword struct propria del linguaggio C. Le sintassi sono: //DICHIARAZIONE DELLA STRUTTURA (come e’ composta, ma non crea nessuna variabile) struct NOMESTRUTTURA { TIPO NOMEVARIABILE; TIPO NOMEVARIABILE; … }; //DICHIARAZIONE DI UNA VARIABILE CHE USA LA STRUTTURA struct NOMESTRUTTURA NOMEVARIABILE; In alternativa e’ possibile dichiarare sia la struttura sia la/le variabili che saranno di tale tipo in una sola sintassi struct NOMESTRUTTURA { TIPO NOMEVARIABILE; TIPO NOMEVARIABILE; … }ELENCONOMIVARIABILI; //GLI ELENCHI SONO SEPARATI DA VIRGOLA Se, abbiamo bisogno di gestire 100 carte di identita’, conviene usare un ARRAY DI STRUTTURA struct NOMESTRUTTURA {

Page 116: Lezioni Cocoa

TIPO NOMEVARIABILE; TIPO NOMEVARIABILE; … }NOMEARRAY[DIMENSIONE]; //DICHIARO un certo numero (DIMENSIONE) di strutture accessibili tramite indice dell’array NOMEARRAY, Facciamo un po’ di esempi . Creiamo ad esempio la struttura per “simulare” la nostra carta d’identita’. ESEMPIO (1) //Dichiaro come e’ costituita la struttura struct cartaIdentita{ char nome[101]; //stringa per contenere al massimo 100 caratteri (+1 = NUL) char cognome[101]; char comuneResidenza[51]; int nAnnoNascita; //Anno aaaa int nMeseNascita; // Mese mm int nGiornoNascita; //Giorno gg double nAltezza; //Altezza in metri,centimetri }; //Mi serve una carta di identita’, creo la variabile struct cartaIdentita CartaIdentitaFranco; Ogni volta che nel programma avro’ bisogno di una nuova carta di identita’ da gestire, sara’ sufficiente scrivere struct cartaIdentita CartaIdentitaMarco; In alternativa, se so gia’ prima che gestiro’ solo un certo numero di carte di identita’, posso dichiarare tutto in una sola volta,quindi ESEMPIO (2) //Dichiaro come e’ costituita la struttura e due variabili di tale tipo di dato (cartaIdentita) struct cartaIdentita{ char nome[101]; //stringa per contenere al massimo 100 caratteri (+1 = NUL) char cognome[101]; char comuneResidenza[51]; int nAnnoNascita; //Anno aaaa int nMeseNascita; // Mese mm int nGiornoNascita; //Giorno gg double nAltezza; //Altezza in metri,centimetri } CartaIdentitaFranco, CartaIdentitaMarco; Nel caso in cui, abbiamo bisogno di gestire 1000 carte di identita’, dichiaro un array ESEMPIO (2)

Page 117: Lezioni Cocoa

//Dichiaro un array di strutture, oltre alla definizione della struttura stessa struct cartaIdentita{ char nome[101]; //stringa per contenere al massimo 100 caratteri (+1 = NUL) char cognome[101]; char comuneResidenza[51]; int nAnnoNascita; //Anno aaaa int nMeseNascita; // Mese mm int nGiornoNascita; //Giorno gg double nAltezza; //Altezza in metri,centimetri } carteIdentitaClienti[1000]; //Dichiaro un array di 1000 strutture di tipo cartaIdentita Rappresentazione in memoria della nostra variabile di tipo struttura. Ogni variabile quando viene stanziata (allocata) per poter essere utilizzata all’interno di un programma,occupa una determinata quantita’ di RAM (in funzione del tipo di dato) e viene posizionata in una specifica locazione della nostra memoria ram. Cosa avviene quando definisco in dato di tipo struct e creo un istanza di tale variabile: Dove e’ posizionata in memoria ? Quanta memoria occupa ? Analizziamo l’ESEMPIO (1). La variabile CartaIdentitaFranco sara’ posizionata in memoria in una qualche locazione (possiamo sapere quale usando l’operatore & per farci restituire l’indirizzo di memoria) Quindi per conoscere la locazione di memoria in cui si trova la nostra struttura in questo modo NSLog(“Indirizzo della variabile : %p”,& CartaIdentitaFranco); Per conoscere la dimensione, uso sizeof() NSLog(“Dimensione della variabile: %d”, sizeof( CartaIdentitaFranco)); Accesso alle variabili contenute nella struttura (VARIABILI MEMBRO) Per accedere ai membri della struttura (le variabili che la compongono) si utilizza l’operatore . (punto) NOMEVARIABILESTRUTTURA.NOMEVARIABILEMEMBRO Esempio Per compilare i dati della struttura CartaIdentitaFranco Dato che alcuni membri della struttura sono delle stringhe C (array di caratteri), uso la funzione standard C per assegnare un testo ad una variabile stringa ossia strcpy(char *strDestinazione,char *strOrigine) strcpy(CartaIdentitaFranco.nome,”Francesco”); //Assegno la stringa Francesco alla variabile membro nome, per accedere alla variabile nome uso operatore . strcpy(CartaIdentitaFranco.cognome,”Germinara”); strcpy(CartaIdentitaFranco.comuneResidenza,”Pinerolo”);

Page 118: Lezioni Cocoa

CartaIdentitaFranco.nAnnoNascita=1966; //Assegno il valore 1966 alla variabile nAnnoNascita di tipo INT CartaIdentitaFranco.nMeseNascita=2; //Assegno il mese CartaIdentitaFranco. nGiornoNascita =20; //Assegno il giorno CartaIdentitaFranco.nAltezza=1.72; //Assegno altezza Per visualizzare il contenuto della variabile CartaIdentitaFranco NSLog(“Carta di identita’: Cognome: ‘%s’ Nome: ‘%s’ Residente: ‘%s’ Nato il: %02d/%02d%04d Alto: %6.2f”, CartaIdentitaFranco.nome, CartaIdentitaFranco.cognome, CartaIdentitaFranco. comuneResidenza, CartaIdentitaFranco. nGiornoNascita, CartaIdentitaFranco. nMeseNascita, CartaIdentitaFranco. nAnnoNascita, CartaIdentitaFranco. nAltezza); Per accedere alle variabili di un array di struttura, e’ sufficiente indicare l’indice dell’array tra parentesi quadre, prima di usare l’operatore . Esempio #define MAX_PERSONE 1200 //definisco una costante numerica struct cartaIdentita elencoVotanti[MAX_PERSONE]; //Istanzio un array di strutture cartaIdentita //Per accedere ai dati della prima carta di identita’ uso indice 0, quindi strcpy(elencoVotanti[0].nome,”Marco”); strcpy(elencoVotanti[0].nome,”Coisson”); //spero non me ne voglia Marco per aver usato i dati //in queso esempio elencoVotanti[0]. nAltezza = 1.74; //Non ne ho idea… invento… … //Per accedere ai dati dell’ultima carta di identità la 1199 esima. strcpy(elencoVotanti[MAX_PERSONE-1].nome,”Franco”);

Page 119: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 10 – Unioni Premessa: non dovete avere mal di testa. Una union e’ una zona di memoria condivisa tra due o piu’ variabili anche di tipo diverso tra di loro, ed e’ molto simile ad una struct (di cui abbiamo parlato la volta scorsa) sia nella dichiarazione sia nell’utilizzo. Per essere chiari, ecco un esempio che compara una struct con una union. //Dichiarazione di una struct struct datiProdotto{ char nome[21]; //Nome del prodotto 20 char char tipo[11]; //Tipologia double prezzo; //Prezzo }unaStrutturaProdotto; //In memoria ho a questo punto costruito qualcosa del genere //[01234567890123456789][0123456789][12345678] // nome tipo prezzo //Totale Memoria Occupata = 21+11+8 = 40 BYTE //Vediamo se e' vero: int nDimStrutturaProdotto=sizeof(struct datiProdotto); NSLog(@"Memoria occupata dalla struttura prodotto: %d\n",nDimStrutturaProdotto); //=40 //Vediamo invece una union union datiProdottoU{ char nome[21]; //Nome del prodotto 20 char char tipo[11]; //Tipologia double prezzo; //Prezzo }unaUnionProdotto; //In memoria questa volta ho costruito qualcosa del genere //[01234567890123456789] nome //[0123456789] tipo //[12345678] prezzo //Quindi tutte e tre le variabili utilizzano la stessa zona di memoria //Il totale della memoria occupata e' quindi quella della variabile che occupa piu' memoria //e non dalla somma delle quantita //Totale Memoria Occupata = 21 BYTE (la variabile che occupa piu' spazio e' nome di 21 Byte) //Vediamo se e' vero: int nDimUnionProdotto=sizeof(union datiProdottoU); NSLog(@"Memoria occupata dalla union prodotto: %d\n",nDimUnionProdotto); //Gulp ! = 24 !!! //Bene, 24 e' comunque vicino a 21, che e' il valore che avevo previsto, ma perche' e 24 ? //Il computer per ottimizzare la velocita' di esecuzione nelle operazioni che riguardano //la copia o lo spostamento dei dati nella memoria, preferisce avere a che fare con dimensioni

Page 120: Lezioni Cocoa

//di dati che siano dei multipli un INT. //Tale comportamento relativo alle struct ed alle union e' chiamato "BYTE ALLIGNED" e puo' essere //modificato tramite opportune opzioni del compilatore. //Consiglio a chi fosse interessato di consultare il manuale del compilatore //Assegnamo dei valori alla union e vediamo come si comporta strcpy(unaUnionProdotto.nome,"Lamponi e Fragole"); //Vediamo cosa contiene la nostra union NSLog(@"unaUnionProdotto.nome = '%s'\n",unaUnionProdotto.nome); //Ora assegno il valore alla seconda variabile ... strcpy(unaUnionProdotto.tipo,"Frutta"); //Vediamo cosa contiene la nostra union NSLog(@"unaUnionProdotto.nome = '%s'\n",unaUnionProdotto.nome); //Vediamo cosa contiene la nostra union NSLog(@"unaUnionProdotto.tipo = '%s'\n",unaUnionProdotto.tipo); //DATO CHE LA ZONA DI MEMORIA E' LA STESSA, QUANDO ASSEGNO IL VALORE A TIPO, VADO //AUTOMATICAMENTE A MODIFICARE IL VALORE DI NOME //In realta' in memoria dovrei avere questa situazione //0-------------------------------24 //Lamponi e Fragole'\0' Dopo la prima assegnazione //Frutta'\0' e Fragole'\0' Dopo la seconda assegnazione //Dato che sono delle stringhe C, ossia null terminated, chiuse quindi dal carattere 0x00 (NUL) //quando chiedo la stampa del contenuto della variabile con NSLog() ottengo Frutta //Cosa succede se ora assegno un valore numerico a prezzo ? Vediamo. unaUnionProdotto.prezzo=1200; //Vediamo cosa contiene la nostra union NSLog(@"unaUnionProdotto.nome = '%s'\n",unaUnionProdotto.nome); // '@í¿' NSLog(@"unaUnionProdotto.tipo = '%s'\n",unaUnionProdotto.tipo); // '@í¿' NSLog(@"unaUnionProdotto.prezzo = '%.0f'\n",unaUnionProdotto.prezzo); // 1200 //Quindi ogni assegnazione che vado a fare ad una variabile, comporta la modifica del contenuto //anche delle altre variabili, questo e' dovuto al fatto che TUTTE le variabili stanno //PUNTANDO alla stessa zona di memoria. //Controlliamo se e' vero ... NSLog(@"\n\nTutte le variabili della struct puntano ad una locazione propria della memoria\n"); NSLog(@"Indirizzo unaStrutturaProdotto.nome = 0x%x\n",&unaStrutturaProdotto.nome); NSLog(@"Indirizzo unaStrutturaProdotto.tipo = 0x%x\n",&unaStrutturaProdotto.tipo); NSLog(@"Indirizzo unaStrutturaProdotto.prezzo = 0x%x\n",&unaStrutturaProdotto.prezzo); NSLog(@"\n\nTutte le variabili della union puntano alla stezza locazione di inizio della memoria\n"); NSLog(@"Indirizzo unaUnionProdotto.nome = 0x%x\n",&unaUnionProdotto.nome);

Page 121: Lezioni Cocoa

NSLog(@"Indirizzo unaUnionProdotto.tipo = 0x%x\n",&unaUnionProdotto.tipo); NSLog(@"Indirizzo unaUnionProdotto.prezzo = 0x%x\n",&unaUnionProdotto.prezzo); Ora che abbiamo appreso come funziona una union, la domanda e’ “a cosa serve ?” Bene, diciamo che e’ molto utile per fare delle conversioni dati, quando si lavora con i singoli byte o bit. Esempio: Ho un numero intero, tale numero e’ rappresentato in memoria (sul nostro Mac) da 4 BYTE (lo abbiamo visto ad inizio corso), voglio conoscere il valore dei singoli byte. Una possibile soluzione consiste nell’utilizzare una union. In pratica “sovrappongo” una variabile int e un array di 4 unsigned char. //Dichiaro una union come composta da un int e da 4 unsigned char union convInt{ int nValore; unsigned char byte[4]; }dato; //Assegno il valore all'intero dato.nValore=168987384; //Leggo il valore dell'intero NSLog(@"Valore di nValore = %d\n",dato.nValore); //Leggo il valore dell'intero come rappresentato dai 4 BYTE in memoria NSLog(@"Valore di nValore = %d BYTE0: %d BYTE1: %d BYTE2: %d BYTE3: %d \n",dato.nValore,dato.byte[0],dato.byte[1],dato.byte[2],dato.byte[3]); A questo punto il problema che ci eravamo posti e’ stato risolto. E se volessi calcolare il valore di un int conoscendo i valori dei singoli byte che lo rappresentano ? Per convertire il valore rappresentato in BYTE in un int e' sufficiente moltiplicare il valore di ciascun byte per le potenze di 256 descrescenti a partire da 3 //quindi valoreIntero= byte0 * 256^3 + byte1*256^2+byte2*256^1+byte3*256^0 //semplificando (in quanto 256^1 = 256 e 256^0=1) //valoreIntero= byte0 * 256^3 + byte1*256^2+byte2*256+byte3 int aValoreRappresentato=(dato.byte[0] * pow(256,3)) + (dato.byte[1] * pow(256,2)) + (dato.byte[2] * pow(256,1)) + (dato.byte[3] * pow(256,0)); NSLog(@"valore rappresentato: %d",aValoreRappresentato); Bene, ovviamente se modifico il valore di un byte della union, cambiera’ il valore della variabile intero in essa presente. //Se cambio il valore di un byte, cambia anche il valore dell'intero presente nella union dato.byte[0]=0; dato.byte[1]=0; dato.byte[2]=2;

Page 122: Lezioni Cocoa

dato.byte[3]=128; NSLog(@"Valore di nValore = %d\n",dato.nValore); ora vale 640 (provate a calcolarlo con il metodo sopra descritto…) Per i piu’ curiosi e volenterosi Se dovessimo rappresentare il valore binario di un carattere, come possiamo fare, usando le struct e le union esiste una semplice soluzione, che trovate nell’esempio legato a questa lezione. Provare a farlo senza guardare la soluzione! Chi vuole potrebbe implementare il programma CheCarattere creato in una delle scorse puntate aggiungendo la possibilita’ di visualizzare anche il valore binario dei caratteri e renderlo disponibile anche agli altri. Saluti.

Page 123: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 11– Enumerazioni e Tipi dati utente Una enumerazione e’ un elenco di costanti intere a cui, per ciascun valore numerico, e’ stato assegnato un nome . Nella realizzazione di programmi, ci troviamo spesso, per comodita’, a dover utilizzare dei valori numerici interi, consecutivi (0,1,2,3...) per rappresentare determinati valori che numerici non sono. Ad esempio un elenco di colori, un elenco di categorie di libri o l’elenco delle monete relative all’Euro (5,10,20,50 centesimi, 1,2 euro). Per motivi di LEGGIBILITA’ conviene utilizzare una COSTANTE numerica (che ha quindi un NOME) piuttosto che utilizzare il solo valore numerico che rappresenta ciascun elemento dell’elenco. Nota: Con il termine Leggibilita’ si intende sostanzialmente questo: - chi legge il sorgente di un programma non e’ detto che sia la stessa persona che lo ha scritto - a distanza di anni potreste riprendere in mano un vecchio programma per modificarlo Conosciamo gia’ un modo per poter fare questo (assegnare un NOME ad un valore numerico), utilizzando la parola chiave #define NOMECOSTANTE valore Esempio: #define ROSSO 2 #define VERDE 3 ma esiste un sistema ancora piu’ efficace: l’uso della parola chiave enum. Una enumerazione si definisce nel seguente modo: //Definizione della enum enum tag{ nomeelemento, nomeelemento, nomelemento, … }; //Dichiarazione di una variabile di tipo enum enum tag nomevariabile; oppure, tutto insieme… enum tag{ nomeelemento, nomeelemento, nomeelemento… }listavariabili; Esempio:

Page 124: Lezioni Cocoa

Una enumerazione di categorie di libri enum genere{ fantascienza, giallo, avventura, fantasia, informatica } genereDiLibro; Tramite questa dichiarazione, ogni elemento della enum ora e’ rappresentato da un valore numerico intero, a partire da zero e che si incrementa di 1 per ogni elemento successivo della lista. Quindi fantascienza vale 0, giallo=1, avventura=2 ecc. Controlliamo se e’ vero … Da XCODE creaimo un nuovo progetto, cocoa application, quindi nel file main.m andiamo a dichiarare la nostra enum e con NSLog vediamo i valori numerici corrispondenti dei vari elementi. int main(int argc, char *argv[]) { //Dichiarazione dell'enum enum genere{ fantascienza, //=0 giallo, //=1 avventura, //=2 fantasia, //=3 informatica //=4 }genereDiLibro; //Dichiarazione della variabile NSLog(@"Valore dell'elemento informatica = %d",informatica); return NSApplicationMain(argc, (const char **) argv); } Eseguiamo ed ecco il risultato … 2006-07-02 10:28:00.048 Enumerazioni[943] Valore dell'elemento informatica = 4 Quanto vale la nostra variabile genereDiLibro ? NSLog(@"Valore della variabile genereDiLibro: %d ",genereDiLibro); //Bho ? Non e' stata assegnata! Quindi dipendera' da quello che trova in memoria Infatti ecco il mio log 2006-07-02 10:30:35.339 Enumerazioni[947] Valore della variabile genereDiLibro: 7468 Bene, inizializziamola genereDiLibro=informatica; //Inizializzo la variabile con un elemento della enum NSLog(@"Valore della variabile genereDiLibro: %d ",genereDiLibro); //Ora vale informatica cioe' 4. Verifichiamo… [Session started at 2006-07-02 10:33:01 +0200.] 2006-07-02 10:33:01.488 Enumerazioni[966] Valore dell'elemento informatica = 4

Page 125: Lezioni Cocoa

2006-07-02 10:33:01.488 Enumerazioni[966] Valore della variabile genereDiLibro: 7468 2006-07-02 10:33:01.488 Enumerazioni[966] Valore della variabile genereDiLibro: 4 In sintesi, ora e’ possibile utilizzare il nome degli elementi della enum, in qualsiasi espressione invece di usare il valore numerico, migliorandone la leggibilità e riducendo la possibilità di errori nel programma. Esempio: Se devo controllare se un dato libro e’ di informatica scrivero’ qualcosa del genere … if( genereDiLibro == informatica) NSLog(@"Genere di libro: informatica"); che e’ molto piu’ chiaro di if( genereDiLibro == 4) NSLog(@"Genere di libro: informatica"); Per i piu’ curiosi E’ possibile far partire l’indice dei valori da assegnare agli elementi della enum con un valore numerico intero qualsiasi (se non viene specificato nulla, parte da 0). Esempio enum colors{ rosso=100, verde, gialloC, //Ho gia’ giallo definito nella enum genere devo dare un altro nome ! marrone=0, nero, bianco }; NSLog(@"Rosso: %d Verde: %d Giallo: %d Marrone: %d Nero: %d Bianco: %d", rosso,verde,gialloC,marrone,nero,bianco); E’ questo e’ il risultato del log 2006-07-02 10:40:51.803 Enumerazioni[994] Rosso: 100 Verde: 101 Giallo: 102 Marrone: 0 Nero: 1 Bianco: 2 TYPEDEF – Tipi dati utente Nella vita reale, spesso amiamo dare nomi diversi alle persone o alle cose, per renderle piu’ facili da ricordare o per “evidenziarne” delle caratteristiche. Bene, in informatica possiamo fare anche questo, con i nostri tipi di dato. Se, ad esempio, invece di usare il nome double per identificare una variabile di tipo numerica reale che poi uso per dichiarare delle variabili relative al mio stipendio, voglio creare un tipo di variabile che si chiami stipendio devo usare la parola chiave typedef per creare un mio tipo di dati personalizzato.

Page 126: Lezioni Cocoa

La sintassi e’ la seguente typedef nometipodatobase nuovonome; quindi, per l’esempio citato sopra: typedef double stipendio; //Creo un nuovo tipo dato che si chiama stipendio Per utilizzarlo //Dati definiti da utente typedef double stipendio; stipendio meseGennaio=120.0; stipendio meseFebbraio=180.0; stipendio meseMarzo=220.0; stipendio medio=0.0; medio =( meseGennaio + meseFebbraio + meseMarzo) /3.0; NSLog(@"Stipendio Medio: %.2f",medio); L’utilizzo di typedef ha un duplice scopo: 1 – migliora la leggibilita’ e la comprensione del codice 2 - facilita la migrazione del programma tra i sistemi (es. Mac os x, Unix, Linux, Windows) questa caratteristica dei programmi si chiama PORTABILITA’. Se il programma deve funzionare invece che su un Mac su un sistema che non conosce il tipo dati double, ma usa solo float, e’ sufficiente cambiare la sola istruzione typedef double stipendio; con typedef float stipendio; e tutto funzionerà regolarmente. Se, invece abbiamo scritto double meseGennaio=120.0; double meseFebbraio=180.0; double meseMarzo=220.0; dobbiamo cambiare tutte le istruzioni dove compare il tipo dato double con il tipo dato float, operazione piu’ lunga e piu’ soggetta ad errori. Normalmente non si procede alla ridefinizione dei tipi di dati base a meno che non si abbia gia’ in mente di creare un software portabile su piu’ piattaforme. Un uso molto comune del typedef e’ invece quello di assegnare un proprio tipo di dato ad un struttura dati. In una delle precedenti puntate abbiamo esaminato le struct, che sostanzialmente ci consentono di “raggruppare” delle variabili logicamente legate tra di loro. Riprendo l’esempio della carta di identita’… struct cartaIdentita{ char nome[101]; //stringa per contenere al massimo 100 caratteri (+1 = NUL) char cognome[101]; char comuneResidenza[51]; int nAnnoNascita; //Anno aaaa int nMeseNascita; // Mese mm

Page 127: Lezioni Cocoa

int nGiornoNascita; //Giorno gg double nAltezza; //Altezza in metri,centimetri }; Questa e’ la definizione della nostra struttura dati da gestire, come abbiamo visto la volta scorsa, ogni volta che mi serve una variabile per contenere tale struttura dati, devo fare una dichiarazione di questo tipo struct cartaIdentita CartaIdentitaFranco; //Creo la variabile A questo punto posso lavorare sulla variabile CartaIdentitaFranco. L’uso dell’istruzione typedef, ci consente di creare un tipo dati typedef struct cartaIdentita cIdentita; quindi ora per creare la variabile di tipo cartaIdentita, e’ necessario indicare solo cIdentita CartaIdentitaFranco; Riepilogo la differenza:

1) senza usare typedef

struct cartaIdentita CartaIdentitaFranco; //Creo la variabile struct cartaIdentita CartaIdentitaRossi; //Creo la variabile struct cartaIdentita CartaIdentitaMarco; //Creo la variabile //Assegno i valori …

strcpy(CartaIdentitaFranco.nome,”Francesco”); … 2) usando typedef

cIdentita CartaIdentitaFranco; cIdentita CartaIdentitaRossi; cIdentita CartaIdentitaMarco; //Assegno i valori …

strcpy(CartaIdentitaFranco.nome,”Francesco”); … Il vantaggio che abbiamo e’ quello di scrivere meno (non devo ripetere struct ogni volta) e di rendere un codice piu’ leggibile.

Generalmemente nel momento stesso un cui si definisce la struttura, si assegna il nome con typedef, cosi’ risparmio ulteriori istuzioni. typedef struct cartaIdentita{ char nome[101]; //stringa per contenere al massimo 100 caratteri (+1 = NUL) char cognome[101]; char comuneResidenza[51]; int nAnnoNascita; //Anno aaaa int nMeseNascita; // Mese mm int nGiornoNascita; //Giorno gg double nAltezza; //Altezza in metri,centimetri } cIdentita; cIdentita fg;

Page 128: Lezioni Cocoa

strcpy(fg.nome,"Francesco"); NSLog(@"nome: %s",fg.nome); Concludo segnalando la possilita’ di utilizzare typedef anche per le enum e le union. Questo e’ un esempio preso pari-pari dalla classe NSButtonCell, che definisce i possibili tipi di pulsanti utilizzabili tramite Cocoa. typedef enum _NSButtonType { NSMomentaryLightButton = 0, // was NSMomentaryPushButton NSPushOnPushOffButton = 1, NSToggleButton = 2, NSSwitchButton = 3, NSRadioButton = 4, NSMomentaryChangeButton = 5, NSOnOffButton = 6, NSMomentaryPushInButton = 7, // was NSMomentaryLight /* These constants were accidentally reversed so that NSMomentaryPushButton lit and NSMomentaryLight pushed. These names are now deprecated */ NSMomentaryPushButton = 0, NSMomentaryLight = 7 } NSButtonType; Questi significa che ogni volta che nel programma voglio impostare un tipo di pulsante potro’ utilizzare il tipo dato NSButtonType. Esempio: NSButtonType tipoDiMioPulsante; //Dichiaro la variabile tipoDiMioPulsante //Di tipo enum _NSButtonType tipoDiMioPulsante = NSMomentaryLight; //Assegno il valore alla mia variabile //Uso uno dei valori previsti dalla Apple NSLog(@"tipoDiMioPulsante: %d",tipoDiMioPulsante); //vale 7. Con questa puntata si conclude il ciclo relativo ai dati ed alle variabili, dalla prossima iniziamo a parlare delle istruzioni del linguaggio. (STATEMENTS). Saluti.

Page 129: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 12– Statements

Mi sveglio, vado in bagno, doccia, colazione.

Per colazione, preparo il caffe’, accendo il gas, se e’ acceso metto la caffettiera sopra il fornello ed

aspetto. Aspetto sino a quando non sento la caffettiera brontolare, mi alzo, se il caffe’ e’ salito

spengo il fornello del gas.

Bevo il caffe’.

Cerco le chiavi della macchina sino a quando non le trovo. Scendo, guido sino all’ufficio, incontro

un semaforo, se e’ verde, passo, se e’ rosso mi fermo (…ehm… una volta mi sono distratto e sono

passato con il rosso, mi e’ costata una multa salata e 6 punti sulla patente…).

Arrivo nel piazzale dell’ufficio, ma e’ tutto pieno, allora giro, giro, giro sino a quando non si libera

un posto. Parcheggio. Lavoro, poi rientro a casa, se e’ pronta la cena, mangio, altrimenti improvviso

qualche piatto veloce. Un po’ di TV (o di Mac ((vedi stasera…)) ) poi vado a dormire.

Un programma, come nella vita reale, non e’ quasi mai sequenziale.

Ha un inizio, uno svolgimento ed un termine e ciascuna di queste parti si evolve in modo diverso

in base a come si presentano determinate situazioni o eventi.

Gli statements, non sono altro che istruzioni che interessano lo svolgimento di alcune parti del

programma, potremmo paragonarli a delle azioni che possono essere compiute e che influenzano lo

svolgimento del programma stesso.

Gli statements possono essere raggruppati in

- decisionali - if, if else if, ?, switch

- iterazioni - for, while,do while

- salti - return,goto,break,continue

- etichette - nomeetichetta:

- espressioni - una espressione terminata con;

- blocchi - { }

Un programma ha sempre un inizio, e nel nostro caso (objectivec & cocoa) e’ rappresentato da

queste poche righe inserire in modo automatico da xcode, nel file main.m

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])

{

return NSApplicationMain(argc, (const char **) argv);

}

Per fare il paragone di quanto scritto all’inzio,

“Mi sveglio” equivale a “utente manda in esecuzione il programma”,quindi il programma si sveglia,

ossia esegue il codice sopra specificato o per essere piu’ precisi esegue la funzione

int main(int argc, char *argv[]).

Cosa significa, praticamente viene creato (istanziato) un primo oggetto di tipo (NSApplication).

Tale oggetto rappresenta il punto di risveglio del programma, o meglio, il punto di INGRESSO nel

programma, tale oggetto e di conseguenza il programma restera’ attivo siano a quando l’utente non

decidera’ di CHIUDERE l’applicazione.

Page 130: Lezioni Cocoa

La chiusura dell’applicazione corrisponde alla parte finale della storiella iniziale (…poi vado a

dormire).

Per verificare che, quando eseguo un programma, appena esso e’ eseguito il codice e’ proprio

quello indicato sopra, facciamo un esperimento.

Usiamo l’istruzione NSLog(@"Programma partito"); per far scrivere nel file di Log

dell’applicazione un messaggio quando il programma e’ eseguito.

Quindi, individuiamo il file main.m e modifichiamo il codice in questo modo

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])

{

NSLog(@"Programma partito");

return NSApplicationMain(argc, (const char **) argv);

}

Compiliamo il programma (Build e Run) e guardiamo cosa succede:

Compare la classica finestra vuota e nel file di run log

[Session started at 2006-07-20 22:34:47 +0200.]

2006-07-20 22:34:47.983 statements[367] Programma partito

Bene, e quando termina ? Bella domanda.

L’istruzione return NSApplicationMain(argc, (const char **) argv); dobbiamo immaginarla composta da queste parti

//1: Variabile di tipo int

int valoreRestituito=0;

//2: esegue la funzione NSApplicationMain ed assegna il valore restituito dalla

funzione alla variabile valoreRestituito;

valoreRestituito=NSApplicationMain(argc, (const char **) argv)

//3: esce dal blocco corrente (un blocco e’ una parte di codice compresa tra

aperta e chiusa parentesi graffa) restituendo il valore della variabile

valoreRestituito

return valoreRestituito;

dato che il blocco di programma da cui si esce e’ il main(){ } il programma

termina la propria esecuzione restituendo al sistema operativo, il codice di

ritorno (valoreRestituito).

Se, quindi, desiderassi visualizzare un messaggio “programma terminato” quando il programma e’

prossimo al termine della sua esecuzione, usando NSLog(@"Programma terminato"); probabilmente cercherei di scrive qualcosa del genere

#import <Cocoa/Cocoa.h>

Page 131: Lezioni Cocoa

int main(int argc, char *argv[])

{

NSLog(@"Programma partito");

return NSApplicationMain(argc, (const char **) argv);

NSLog(@"Programma terminato"); //NON FUNZIONA! Questa istruzione non sara’

//mai eseguita, in quanto e’ stata incontrata

//una istruzione return che ha causato

//l’uscita da questo blocco,

}

Provare per credere…

Bene, modifichiamo leggermente il codice in modo da poter intercettare il momento della

terminazione dell’applicazione, per fare cio’ e’ necessario commentare la riga in cui viene effettuata

la chiamata a NSApplicationMain() che crea ed esegue l’applicazione cocoa.

Nota: date un occhiata alla documentazione Apple relative al tale funzione.

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])

{

NSLog(@"Programma partito");

// return NSApplicationMain(argc, (const char **) argv);

NSLog(@"Programma terminato");

return 0;

}

Compiliamo ed eseguiamo, ora il risultato e’ che NON compare nessuna finestra, il programma

parte e termina istantaneamente; e’ esattamente cio’ che gli abbiamo chiesto di fare, ossia

SVEGLIATI, scrivi PROGRAMMA PARTITO, scrivi PROGRAMMA TERMINATO,vai a

dormire.

Il run log e’ il seguente

[Session started at 2006-07-20 23:00:06 +0200.]

2006-07-20 23:00:06.903 statements[494] Programma partito

2006-07-20 23:00:06.903 statements[494] Programma terminato

statements has exited with status 0.

Notare la riga che dice che il programma statements e’ uscito (e’ terminato) con lo stato 0! Zero e’

infatti il valore che noi abbiamo indicato nella nostra istruzione return. (se metto 23…)

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])

{

NSLog(@"Programma partito");

Page 132: Lezioni Cocoa

// return NSApplicationMain(argc, (const char **) argv);

NSLog(@"Programma terminato");

return 23;

}

[Session started at 2006-07-20 23:01:43 +0200.]

2006-07-20 23:01:43.453 statements[513] Programma partito

2006-07-20 23:01:43.454 statements[513] Programma terminato

statements has exited with status 23.

Il codice di uscita del programma puo’ essere intercettato da altri programmi o dal sistema

operativo per valutarne il valore ed effettuare o meno determinate attività, ma questo non ci

interessa (...per il momento…)

Ritorniamo alla storiella iniziale; e proviamo a farne il programma…

Mi sveglio int main(int argc, char *argv[]){

vado in bagno,

vaiInBagno(); //Eseguo la funzione

doccia,

faiDoccia(); //Eseguo la funzione

colazione

faiColazione();//Eseguo la funzione

cerco le chiavi della macchina, sino a quando non le trovo…

BOOL bHoLeChiaviDellaMacchina=FALSE;

while(bHoLeChiaviDellaMacchina!=TRUE){

bHoLeChiaviDellaMacchina=cercaChiaviDellaMacchina();

}

incontro un semaforo, se e’ verde, passo, se e’ rosso mi fermo

BOOL bSemaforoVerde=FALSE;

if(bSemaforoVerde == FALSE){

aspetto();

}else{

parcheggio();

}

Un po’ di TV (o di Mac ((vedi stasera…)) )

NSLog(@"un po' di TV o MAC...");

poi vado a dormire NSLog(@"Programma terminato (=poi vado a dormire)");

return 23;

Page 133: Lezioni Cocoa

}

Questo e’ il run log del programma

[Session started at 2006-07-20 23:42:58 +0200.]

2006-07-20 23:42:58.071 statements[742] Programma partito

2006-07-20 23:42:58.072 statements[742] Sono in bagno!

2006-07-20 23:42:58.072 statements[742] Sono sotto la doccia!

2006-07-20 23:42:58.072 statements[742] Metto il caffe'

2006-07-20 23:42:58.072 statements[742] guido...

2006-07-20 23:42:58.072 statements[742] semaforo rosso...aspetto...5 secondi

2006-07-20 23:43:03.072 statements[742] semaforo Verde!

2006-07-20 23:43:03.072 statements[742] lavoro...

2006-07-20 23:43:03.072 statements[742] cena...

2006-07-20 23:43:03.072 statements[742] un po' di TV o MAC...

2006-07-20 23:43:03.072 statements[742] Programma terminato (=poi vado a dormire)

statements has exited with status 23.

Conclusione:

In questa puntata di introduzione agli statements ho cercato di spiegare con un esempio cosa sono e

a cosa servono le varie istruzioni e parti del programma.

Nella prossima puntata, tratteremo i vari statements singolarmente, analizzandone la sintassi ed il

modo di utilizzo in un programma.

Mi auguro di essere stato sufficientemente chiaro e vi saluto.

In allegato il progetto in Xcode 2.3 contenente l’esempio trattato.

Page 134: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 13– Decidere…decidere

Quante volte nell’arco della nostra giornata ci troviamo a dover scegliere, cosa fare in funzione del

verificarsi o meno di determinate condizioni.

Probabilmente e’ una delle attivita’ che facciamo piu’ di frequente, a volte inconsciamente.

Alcune scelte sono molto semplici, banali… se piove prendo l’ombrello, se ho fame mangio, altre

sono piu’ complicate e richiedono la valutazione di differenti condizioni … per attraversare la

strada, considero la presenza o meno di veicoli, la loro velocita’ e la mia, la distanza che devo

percorrere per attraversare e se c’e’ un semaforo, se e’ verde.

In informatica e nella programmazione le cose non cambiano; spesso, molto spesso, dobbiamo

decidere cosa fare in funzione di una condizione (caso semplice) o di molte condizioni (caso piu’

complicato).

Col termine condizione (o test) intendo la valutazione di una espressione che puo’ dare come

risultato sono VERO (TRUE) o FALSO (FALSE).

Esempi

Il semaforo e’ rosso ? (condizione o test da valutare) -> FALSO o VERO (NO/SI)

10 e’ maggiore di 5 ?

Ci sono macchine che arrivano ?

In linguaggio C e suoi derivati, esistono delle costanti che identificano il valore VERO o FALSO di

una condizione, e sono, ad esempio true,TRUE,YES,valore diverso da zero oppure

false,FALSE,NO,valore 0.

La prima istruzione che incontriamo per valutare una condizione di test e’ la if/else

ISTRUZIONE IF/ELSE

La sintassi dell’istruzione e’

1)

if(espressione di test)

istruzione eseguita se il risultato e’ VERO;

else

istruzione eseguita se il risultato e’ FALSO;

Se ho piu’ di una sola istruzione, si utilizzano le istruzioni di blocco {} per racchiudere l’elenco

delle istruzioni da eseguire, la sintassi in questo caso e’

2)

if(espressione di test){ //Eseguite se il risultato dell’espressione e’ VERO

istruzione1;

istruzione2;

istruzione3;

}else{ //Eseguite se il risultato dell’espressione e’ FALSO

istruzione1;

istruzione4;

}

Page 135: Lezioni Cocoa

Non e’ sempre necessario indicare l’istruzione else, dipende dalle situazioni, per esempio

Esco per andare a comperare un topolino

Se(non ho soldi in tasca)

PassareAlBancomat;

entrare dal giornalaio;

acquistare il topolino;

IMPORTANTE: prestate sempre molta attenzione quando si usa la sintassi 1) in quanto, non

essendo presente un blocco di istruzioni (delimitato da aperta e chiusa graffa), sara’ eseguita una

sola istruzione.

E’ anche possibile “annidare” delle istruzioni if, complicando la leggibilita’ del codice; la sintassi in

questo caso e’ la seguente

3)

If(espressione)

If(espressione2)

If(espressione3)

Istruzione;

Esempio

Se(semaforoVerde)

Se(arrivaUnaMaccchina)

Se(vaPiano)

attraversoLaStrada;

ed anche annidare delle istruzioni if else if

4)

if(espressione)

istruzioneSeVeroEspressione1;

else if (espressione2)

istruzioneSeVeroEspressione2;

else if (espressione3)

istruzioneSeVeroEspressione3;

else

istruzioneSeFalso;

Per esercitarvi con questo primo approccio alle decisioni, trovate in allegato un progetto da

compilare in XCODE 2.3 o successivo, completo di sorgenti.

A presto.

Videata del programma

Page 136: Lezioni Cocoa

Codice esempio

- (IBAction)valutaSituazione:(id)sender{ //Questo metodo e' chiamato, a seconda

dei casi da

//

chkBoxSemaforoVerde2,chkBoxArrivaUnAuto2 o chkBoxVaPiano2

BOOL bStatoSemaforo=[chkBoxSemaforoVerde2 state];

BOOL bArrivaUnAuto=[chkBoxArrivaUnAuto2 state];

BOOL bVaPiano=[chkBoxVaPiano2 state];

//La valutazione che effettuo e' la seguente:

/*

se il semaforo e' ROSSO

FERMO

altrimenti

se arriva un auto

se va piano

ATTRAVERSO

altrimenti

FERMO

altrimenti

ATTRAVERSO

*/

if(bStatoSemaforo == NSOffState){ //Semaforo verde ?

[txtAzione2 setStringValue:@"FERMO!!!"]; //SEMAFORO ROSSO !

}else{ //Ok, e' verde

if(bArrivaUnAuto==NSOnState){ //Ci sono auto ?

if(bVaPiano == NSOnState){ //Si, ci sono. Vanno piano ?

[txtAzione2 setStringValue:@"Puoi attarversare!"]; //Si,vanno piano.Posso

Attraversare

}else{ //Ci sono auto e non vanno piano.

[txtAzione2 setStringValue:@"FERMO!!!"]; //Arriva un auto, veloce. FERMO.

}

}else{ //Il semaforo e' VERDE e non ci sono AUTO. Passo Tranquillo.

[txtAzione2 setStringValue:@"Puoi attarversare!"];

}

}

}

Page 137: Lezioni Cocoa

Il programma di esempio e’ scaricabile al seguente link

http://www.germinara.it/corsoprogrammazione/decidere.zip

Page 138: Lezioni Cocoa

Il programmatore che c’e’ in noi – Lezione 14– Nel caso in cui …

Ho sete, decido di andare a prendere qualcosa ad una delle solite macchinette del caffe’.

Mi ritrovo davanti ad una sfilza di pulsanti, ciascuno corrispondente ad una bevanda, rifletto su cosa

preferisco bere,infilo ma mia bella monetina ed eccomi servito.

Immaginate ora di essere voi la macchinetta in questione, quindi dovrete fare determinate cose

(preparare la bevanda selezionata) in funzione del bottone che e’ stato premuto dalla persona che e’

davanti alla macchinetta.

Si tratta quindi di creare il programma per la macchinetta del caffe’.

Analiziamo la situazione (voi siete la macchinetta):

Macchinetta: aspetto che qualcuno metta dei soldi … uffa… che noia…

Persona: Inserisco un bell’euro, e dopo attenta riflessione, scelgo un caffe’ normale,amaro.

Macchinetta: … uao! Qualcuno a messo dei soldi… sentiamo cosa vuole… aspetto che prema un

bottone

Persona: Premo il bottone, caffe’ normale amaro

Macchinetta: …uhm…vuole un caffe’ amaro, che costa 0,50 euro…ha messo 1 euro, quindi ok…

spettacolo… posso preparare un bel caffe’… devo anche dare il resto 0.50…

Persona: Prendo il resto e prelevo la bevanda.

Una buona parte delle operazioni sopra descritte puo’ essere trasformata in un programma

utilizzando le istruzioni if ed else viste in precedenza. Nel momento in cui la macchinetta deve

valutare quale bottone e’ stato premuto conviene utilizzare un'altra istruzione di valutazione della

condizione.

La convenienza risiede unicamente nel fatto di poter scrivere un codice piu’ leggibile ed a volte piu’

breve rispetto ad utilizzare una serie di if.

Tale istruzione e’ SWITCH

IMPORTANTE

Per poter utilizzare l’istruzione switch e’ indispensabile che il valore da valutare sia una

valore numerico intero oppure una variabile di tipo carattere.

Sintassi:

switch(valore da valutare){

case costante1:

prima istruzione da eseguire;

seconda istruzione da eseguire;

break;

case costante2:

Page 139: Lezioni Cocoa

prima istruzione da eseguire;

break;

… altri case…

default:

istruzioni eseguite se il valore non corrisponde a nessuno dei valori indicati nelle precedenti

istruzioni case

}

Esempio:

La nostra macchinetta ci consente di scegliere tra le seguenti bevande

1 Caffe’ Normale Amaro

2 Caffe’ Lungo Amaro

3 Caffe’ Normale Dolce

4 Caffe’ Lungo Dolce

5 Caffe’ macchiato

6 The al limone

7 The alla pesca

8 Cioccolata

9 Cioccolata e Latte

Di conseguenza, quando viene premuto un pulsante (tra 1 e 9), la macchinetta deve preparare la

relativa bevanda.

Il programma addatto ad effettuare tale operazione potrebbe essere del tipo

int nNumeroBottonePremuto=0;

nNumeroBottonePremuto=UtenteSceglieBevanda(); //Restituisce il numero del pulsante premuto

//Valutiamo quale bevanda e’ stata scelta

1) MODO: Usiamo IF

if(nNumeroBottonePremuto == 1){

//utente ha scelto il Caffe’ Normale Amaro

}

if(nNumeroBottonePremuto == 2){

//utente ha scelto il Caffe’ Lungo Amaro

}

if(nNumeroBottonePremuto == 3){

//utente ha scelto il Caffe’ Normale Dolce

}

if(nNumeroBottonePremuto == 4){

//utente ha scelto il Caffe’ Lungo Dolce

}

Page 140: Lezioni Cocoa

if(nNumeroBottonePremuto == 5){

//utente ha scelto il Caffe’ macchiato

}

if(nNumeroBottonePremuto == 6){

//utente ha scelto il The al limone

}

if(nNumeroBottonePremuto == 7){

//utente ha scelto il The alla pesca

}

if(nNumeroBottonePremuto == 8){

//utente ha scelto la Cioccolata

}

if(nNumeroBottonePremuto == 8){

//utente ha scelto Cioccolata e Latte

}

2) MODO: Usiamo SWITCH

switch(nNumeroBottonePremuto){

case 1: //utente ha scelto il Caffe’ Normale Amaro

break;

case 2: //utente ha scelto il Caffe’ Normale Amaro

break;

case 3: //utente ha scelto il Caffe’ Normale Amaro

break;

case 4: //utente ha scelto il Caffe’ Normale Amaro

break;

case 5: //utente ha scelto il Caffe’ Normale Amaro

break;

case 6: //utente ha scelto il Caffe’ Normale Amaro

break;

case 7: //utente ha scelto il Caffe’ Normale Amaro

break;

case 8: //utente ha scelto il Caffe’ Normale Amaro

break;

case 9: //utente ha scelto il Caffe’ Normale Amaro

break;

default:

//errore nella selezione. (ha premuto un pulsante non compreso tra 1 e 9)

}

IMPORTANTE

L’istruzione default, all’interno dello switch e’ facoltativa.

Page 141: Lezioni Cocoa

L’istruzione break all’interno di uno switch provoca uscita dal blocco dello switch stesso

(compreso tra { e } ) o, in altri termini, provoca il salto del codice da eseguire alla prima istruzione

presente alla fine del blocco dello switch.

Se a piu’ valori corrispondono le stesse istruzioni, si puo’ scrivere lo switch nel modo seguente

swicth(nNumeroBottonePremuto){

case 1:

case 2:

//istruzioni da eseguire, indipendentemente se ho premuto 1 o 2

break;

case 3:

//istruzione da eseguire se ho premuto 3

break;

}

Per concludere, vediamo l’esempio utilizzando una variabile di tipo carattere come elemento da

valutare nello switch.

char chMenuScelto;

//supponiamo che l’utente possa scegliere una voce di menu, premendo la prima lettera iniziale

//Immissione dati

//Variazione dati

//Cancellazione

//Stampa

//Esci

chMenuScelto=getSceltaUtente(); //Restituisce il carattere corrispondente alla scelta del menu

switch(chMenuScelto){

case ‘I’:

//Immissione dati

//istruzioni per gestire l’immissione dati

break;

case ‘V’:

//variazione dati

break;

case ‘S’: //stampa

break;

case ‘E’: //Esci

break;

default:

//Visualizza errore, scelta non valida..

}

Vi lascio con un esempio (la macchinetta del caffe’) implementato in Cocoa, su cui esercitarvi.

Saluti.