Programmare in rete con Xcode, cocoa, objective-C e iOS

Introduzione

Io ho la necessità per lavoro di crearmi una serie di applicazioni per Mac

e iOS che possano interagire tra di loro e salvare i dati in un database centralizzato

in modo che ci possa poi accedere anche via web attraverso un sito Internet.

Ho girato molto in Internet e non ho trovato frameworks soddisfacenti

per l’accesso diretto a database esterni a cocoa.

Parlando con gli ingegneri Apple, mi hanno suggerito di sfruttare

Internet e per la precisione Apache + PHP + MySQL.

Rimasto frastornato da questa risposta ho chiesto altre delucidazioni e mi

hanno detto di vedermi la sezione di networking del WWDC 2010 e 2011.

Dopo la visione mi si sono aperti gli occhi e ho iniziato a capire come funziona il tutto.

Ci sono ancora cosa che devo provare e chiarire, ma tempo al tempo!

Ed ecco la domanda… Ma come posso realizzare il tutto e fare comodamente delle prove?

Come primo step bisogna avere un server web funzionante a portata di mano.

Si può scegliere di acquistare un dominio e dello spazio Internet presso un qualsiasi ISP

tipo Aruba o kermat.net (sono io!!!), si può scegliere di ammattire per far funzionare

Apache già incluso con Lion oppure ci possiamo affidare ad

un software molto semplice che è MAMP. MAMP è l’acronimo

di Mac Apache Mysql Php, il programma viene distribuito

in due versioni: versione free e a pagamento.

Il tutorial si divide in varie fasi in modo da far capire bene i vari step

e sono organizzati in maniera progressiva:

  • Installazione e configurazione MAMP su Lion;
  • Realizzazione di una pagina di test in PHP;
  • Realizzazione della pagina “botta e risposta” in PHP che chiameremo dall’applicazione;
  • Realizzazione della prima applicazione;
  • Realizzazione della seconda pagina in PHP che salverà i dati dentro MySQL;
  • Realizzazione della seconda applicazione che salverà e richiamerà dei dati da MySQL.

Dopo questa lunga introduzione possiamo iniziare la prima fase del tutorial.

Naturalmente per poter procedere occorre avere la connessione Internet attiva e sapere

installare un programma su ambiente Mac e in particolare su Lion.

Prima di procedere mi sono creato la cartella “ApplicazioneWeb” all’interno dei mie Documenti.

Inizieremo questo lungo viaggio scaricando MAMP dal sito internet

http://www.mamp.info scegliendo la versione free.

Questa versione ci permette di poter creare e controllare un singolo dominio e

la versione a pagamento fino a 15 domini in contemporanea.

Terminato il download dell’applicativo si esegue l’installer facendo

il classico doppio click sul file MAMP.pkg che si trova nella directory download.

Il programma di installazione non richiede scelte particolari da fare quindi bast

a il solito avanti avanti avanti accetto accetto accetto…

Qui potrei inserire degli screeshot per mostrare le fasi

dal download alla conclusione dell’installazione.

Internet

Apache + PHP

MySQL

Ed ecco la domanda… Ma come posso realizzare il tutto e fare comodamente delle prove?

Come primo step bisogna avere un server web funzionante a portata di mano.

Si può scegliere di acquistare un dominio e dello spazio Internet presso un qualsiasi

ISP tipo Aruba o kermat.net (sono io!!!), si può scegliere di ammattire per far funzionare

Apache già incluso con Lion oppure ci possiamo affidare ad un software

molto semplice che è MAMP. MAMP è l’acronimo di Mac Apache Mysql Php,

il programma viene distribuito in due versioni: versione free e a pagamento.

Il tutorial si divide in varie fasi in modo da far capire bene i vari step e

sono organizzati in maniera progressiva:

  • Installazione e configurazione MAMP su Lion;
  • Realizzazione di una pagina di test in PHP;
  • Realizzazione della pagina “botta e risposta” in PHP che chiameremo dall’applicazione;
  • Realizzazione della prima applicazione;
  • Realizzazione della seconda pagina in PHP che salverà i dati dentro MySQL;
  • Realizzazione della seconda applicazione che salverà e richiamerà dei dati da MySQL.

Dopo questa lunga introduzione possiamo iniziare la prima fase del tutorial.

Naturalmente per poter procedere occorre avere la connessione Internet attiva

e sapere installare un programma su ambiente Mac e in particolare su Lion.

Ora che MAMP funziona egregiamente non ci rimane che fare un test di collaudo

scrivendo una piccola pagina in PHP.

Per fare ciò io uso DreamViewer, ma può essere usato qualsiasi programma anche gratuito come Editra.

L’importante è che il nome del file rimanga invariato a come lo scrivo su questa guida.

Prima di passare a scrivere codice su Xcode creiamo la pagina PHP che ci serve richiamare.

Io voglio che nella mia applicazione ci sia un campo di testo dove metterò

il mio nome e cognome (o del testo qualunque) e una label dove i

l programma mi scriverà la risposta di Apache.

Apro il mio editor PHP preferito e scrivo:

<?php

if(  is_array( $_REQUEST ) && isset( $_REQUEST[‘testo’] ) )

{

if( $_REQUEST[‘testo’] != “” )

{

echo “Ciao ” . $_REQUEST[‘testo’];

} else

echo “1001”;

} else

echo “1002”;

?>

Salvo la pagina come il nome di prova.php dentro la directory

ApplicazioneWeb che si trova sempre dentro Documenti.

Il codice controlla che venga passata una url del tipo http://localhost/prova.php?testo=

e in caso contrario restituisce la stringa “1002” che mi servirà sulla

mia applicazione a mostrare il corretto messaggio di errore.

Il codice controlla che ci sia del testo dopo http://localhost/prova.php?testo=

e se non è presente mi restituisce il valore di errore “1001”.

Questi numeri li ho scelti io. E’ quindi possibile cambiarli basta

ricordarsi di fare altrettanto sull’applicazione.

Se tutto è nella norma, ovvero la pagina è stata chiamata con

i parametri giusti e del testo in aggiunta, php resistuirà alla nostra

applicazione la stringa “Ciao, ” più il testo inserito nella nostra applicazione.

Simuliamo il tutto da safari:

Ora non ci rimane che scrivere la nostra applicazione per provare

il passaggio dei datida Xcode verso Apache e poi da Apache verso Xcode.

1 – Apro Xcode e sceglo “Create a new Xcode project  di tipo Cocoa Application

2- Ho deciso di chiamare questa applicazione “TestApache”

3 – Faccio click sul file xib e inizio a creare l’interfaccia grafica

4- L’interfaccia grafica conclusa. Ha due label, un TextField e un PushButton

5 – Inizio a creare la nuova classe: File -> New -> New File.->Objective-c class

Chiamo la classe “TestHTTP” e la dichiaro sottoclasse di “NSBobject”. Alla schermata successiva faccio click su “Create”.

Nel file TestHTTP.h vado a scrivere il seguente codice:

[code lang=”objc”]

#import &lt;Foundation/Foundation.h&gt;

@interface testHTTP : NSObject

{

IBOutlet NSTextField *delTesto;

IBOutlet NSTextField *laRisposta;

}

– (IBAction) testHTTPstart:(id)sender;

@end

[/code]

Ho dichiarato due IBOutlet: uno sarà legato al TextFiled (delTesto) e

l’altro sarà legato alla Label (laRisposta). Ho creato poi un

IBAction per il pulsante.

Nel file TestHTTP.m vado a scrivere il seguente codice ( commenterò una funzione alla volta…):

[code lang=”objc”]

#import &quot;testHTTPclass.h&quot;

NSURLConnection *theConnection;

NSMutableData   *receivedData;

@implementation testHTTPclass

– (id)init

{

self = [super init];

if (self) {

// Initialization code here.

receivedData = [[NSMutableData alloc] init];

}

return self;

}

[/code]

Ho dichiarato due variabili di cui la prima terrà al suo interno la connessione

che stabilirò con Apache e la seconda conterrà il risultato fornito da Apache.

Ho allocato in memoria e poi inizializzato la variabile receivedData

dentro il costrutto in init. le variabili

theConnection e receivedData dichiarate a questo modo le posso usare da funzioni a funzioni ma solo sulla classe.

[code lang=”objc”]

– (IBAction)testHTTPstart:(id)sender

{

NSString *myUrl = [@&quot;&lt;a href=&quot;http://46.31.110.83/test.php?testo=&quot;&gt;http://localhost/prova.php?testo=&lt;/a&gt;&quot; stringByAppendingString:[NSString stringWithFormat:@&quot;%@&quot;, [delTesto stringValue]]];

myUrl =[myUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@&quot;delTesto: %@&quot;,  myUrl);

[laRisposta setStringValue: myUrl];

NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:myUrl]

cachePolicy:NSURLRequestUseProtocolCachePolicy

timeoutInterval:60.0];

theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

}

[/code]

Questa funzione è il cuore della mia classe. Ho inizializzato una stringa

NSString in maniera un po complessa. Nel dettaglio mi serviva creare la stringa per

la connessione ad Apache sommando la stringa “http://localhost/prova.php?testo=” con il contenuto

del TextField. L’intero comando inizializza la variabile myURL

con la stringa “http://localhost/prova.php?testo=” di defualt e a questa viene

aggiunta (stringByAppendingString) una seconda stringa (NSString stringWithFormat:@”%@”)

che risulta essere [delTesto stringValue].

Ho notato che se scrivevo “ciao mondo” nel campo testo poi si incasinava quando

creava la connessione per via dello spazio. Ho quindi usato del codice che mi cambia

il carattere spazio con la dicitura %20 per le url.

Scrivo nel log la variabile myURL per controllare che venga scritta in maniera corretta.

Inizializzo la mia connessione theRequest passandogli come url da chiamare quella che ho generato prima.

Setto un timeout vero il server di 60 secondi, scaduto il quale l’applicazione mi sputa

nella label che non riesce a connettersi al server.

Poi come ultima cosa avvio la mia connessione e imposto la ricezione dei dati da Apache.

[code lang=”objc”]

– (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data

{

[receivedData appendData:data];

NSLog(@&quot;Received chunk of size %zu&quot;, (size_t) [receivedData length] );

}

[/code]

Questa funzione non fa altro che ricevere tutti i segmenti della trasmissione

da parte di apache e aggiungerli di volta in volta alla variabile receivedData

dichiarata in precedenza. Nel log mostra l’andamento dell’operazione.

In questo modo si possono ricevere anche file di grandi dimensioni.

[code lang=”objc”]

– (void)connectionDidFinishLoading:(NSURLConnection *)theConnection

{

NSLog(@&quot;Succeeded! Received %lu bytes of data&quot;,[receivedData length]);

NSString *s = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];

NSLog(@&quot;Stringa: %@&quot;, s);

[laRisposta setStringValue: s];

[receivedData setData:NULL];

}

[/code]

Funzione che viene chiamata alla fine della ricezione dei dati da parte di Apache. Come prima cosa mando un messaggio di successo al log.

Dichiaro e inizializzo una stringa temporanea s con il contenuto di receivedData.

Ho dovuto anche ricodificare la stringa e trasformarla in codice ASCII standard.

Scrivo sul log quello che ho ricevuto da Apache.

Ora non ci rimane che mostrare cosa abbiamo ricevuto da Apache.

Imposto la Label (laRisposta) con il valore contenuto nella variabile dichiarata poco prima s.

Poi per terminare azzero la variabile receivedData. Questo è un passaggio

molto importante perchè altrimenti ogni volta che premo il pulsante mi si

accoderebbe quello che apache mi restituisce.

[code lang=”objc”]

– (void)connection:(NSURLConnection *)theConnection

didFailWithError:(NSError *)error

{

NSLog(@&quot;Connection failed! Error – %@ %@&quot;,

[error localizedDescription],

[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);

}

[/code]

Ultima funzione che viene chiamata nel caso ci sia qualche errore con

la connessione e mi viene scritto tutto nel log.

Ecco ora l’intero codice senza le spiegazioni.

[code lang=”objc”]

#import &quot;testHTTPclass.h&quot;

NSURLConnection *theConnection;

NSMutableData   *receivedData;

@implementation testHTTPclass

– (id)init

{

self = [super init];

if (self) {

receivedData = [[NSMutableData alloc] init];

}

return self;

}

– (IBAction)testHTTP:(id)sender

{

NSString *myUrl = [@&quot;&lt;a href=&quot;http://46.31.110.83/test.php?testo=&quot;&gt;http://46.31.110.83/test.php?testo=&lt;/a&gt;&quot; stringByAppendingString:[NSString stringWithFormat:@&quot;%@&quot;, [delTesto stringValue]]];

myUrl =[myUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@&quot;delTesto: %@&quot;,  myUrl);

NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:myUrl]

cachePolicy:NSURLRequestUseProtocolCachePolicy

timeoutInterval:60.0];

theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

}

– (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data

{

[receivedData appendData:data];

NSLog(@&quot;Received chunk of size %zu&quot;, (size_t) [receivedData length] );

– (void)connectionDidFinishLoading:(NSURLConnection *)theConnection

{

NSLog(@&quot;Succeeded! Received %lu bytes of data&quot;,[receivedData length]);

NSString *s = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];

NSLog(@&quot;Stringa: %@&quot;, s);

[laRisposta setStringValue: s];

[receivedData setData:NULL];

}

– (void)connection:(NSURLConnection *)theConnection

didFailWithError:(NSError *)error

{

NSLog(@&quot;Connection failed! Error – %@ %@&quot;,

[error localizedDescription],

[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);

}

@end

}

[/code]

Occupiamoci ora delle connessioni così da vedere, finalmente, la nostra applicazione funzionare!!!

Rechiamoci nel file . xib e inseriamo  2 text field e un push botton

Aggiungo il famoso cubo blù “Object” e nell’ispector gli associo la classe “TestHTTP”

Ora faccio le solite mosse per creare le connessioni e in questo caso sono tre:

  • Connessione tra la classe e il TextField;
  • Connessione tra la classe e la Label;
  • Connessione tra la classe e il pulsante.

Effettuate le connessioni si può provare il nostro programma

(avviare pirma MAP!!! Altrimenti non funziona!!!)

e se tutto è stato fatto nella maniera giusta otterremo quanto segue: