Come promesso nel precedente tutorial, creeremo oggi un client iOS utilizzando le grandi novità di iOS5, utilizzeremo infatti sia ARC che Storyboard.
Iniziamo creando un nuovo progetto di tipo “Empty application”. Potremmo selezionare anche “Master-detail Application”, ma ci troveremmo troppa pappa pronta e questo non va bene.

Chiamiamo il progetto JSClient e assicuriamoci di aver selezionato “iPhone” e “Use automatic reference counting” come mostrato in foto:

L’applicazione in questo momento è veramente vuota per cui bisogna aggiungere almeno un file storyboard, aggiungiamolo cliccando su file->new file e selezionando la voce “storyboard”:

Attenzione a selezionare iPhone come Device Family.
Dobbiamo ora fare in modo che l’app utilizzi questo file per caricare l’interfaccia e per far ciò selezioniamo l’icona del progetto in alto a sinistra e scegliamo il corretto storyboard dalla combobox Main Storyboard:

C’è un’altra modifica da effettuare affiché venga correttamente utilizzato lo storyboard e consiste nell’eliminare il contenuto del metodo:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Nell’appdelegate, assicuratevi semplicemente di mantenere un:
return TRUE;
Possiamo passare alla creazione dell’interfaccia dentro lo storyboard. Se non l’avete mai utilizzato potete farvi un’idea leggendo l’articolo Introduzione a Storyboard.
Trasciniamo sullo storyboard un UITableViewController e scegliamo “embed in-> navigation controller” dal menù Editor, otterremo questo risultato:

Come abbiamo già detto nel precedente articolo, abbiamo trascinato un generico tableViewController, ma a noi serve una nostra classe che erediti da tableViewController, aggiungiamo quindi un nuovo file al progetto (sempre file->new file) selezionando la voce UIViewController Subclass e scegliendo infine UITableViewController dalla combobox SubClass of:
.A questo punto possiamo specificare all’interno del file storyboard che il tableviewcontroller non è un generico tableviewcontroller, ma una istanza dell’appena inserito MainTableViewController.
Selezioniamolo quindi all’interno del file storyboard e settiamone correttamente la proprietà custom class come mostrato nello screenshot:

Vogliamo che selezionando un contatto dalla tabella venga visualizzata una view con i dettagli di quel contatto. Per questo ci servirà un secondo viewController. Trasciniamo quindi nello storyboard un viewController standard e trasciniamo dalla cella del tableViewController verso il viewController appena creato e selezioniamo “push” dal menù che viene visualizzato. Questo sarà il risultato:

Anche in questo caso abbiamo usato un generico viewController, ma in realtà ci servirà uno specifico viewController, aggiungiamolo quindi da file->new file e poi modifichiamo lo storyboard affinché rispecchi la nuova classe, allo stesso modo di come abbiamo fatto poco fa con il MainTableViewController.
Ci serviranno 4 textField per visualizzare i dettagli del contatto selezionato e per fare ciò sfruttiamo una comoda funzionalità del nuovo XCode, apriamo lo storiboard e trasciniamo 4 textfield sul viewcontroller, selezioniamo la visualizzazione dell’assistant editor e trasciniamo dalle textfield verso l’intestazione della classe:

In questo modo verranno automaticamente create le quattro property necessarie per accedere alle textfield.
Realizzazione della logica applicativa
Possiamo passare ora a realizzare la parte di logica del programma che ci permetterà di scaricare il JSON dal nostro server e visualizzare i contatti nella tabella.
Apriamo il file MainTableViewController e aggiungiamo un’array come variabile di istanza dove memorizzare tutti i contatti:
@property (nonatomic, strong) NSArray *contatti;
non dimentichiamoci:
@synthesize contatti;
nel file MainTableViewController.m.
All’interno del metodo viewDidLoad occupiamoci di interrogare il server per ottenere il JSON, ma non lo faremo nel thread principale, useremo invece il gran central dispatcher per eseguire il download in background. Modifichiamo quindi il metodo in questo modo:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://localhost:8888"]];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES]; });
}
Come potete notare dopo aver scaricato il JSON ed averlo memorizzato all’interno dell’oggetto data richiamiamo fetchedData, che si occuperà di effettuare il parsing.
Il metodo è questo:
- (void)fetchedData:(NSData *)responseData {
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions error:nil];
self.contatti = json;
[self.tableView reloadData];
}
Tutta la magia avviene grazie alla classe NSJSONSerialization ed al suo metodo JSONObjectWithData:options:error che si occupa di parsare il JSON e restituire un array di dizionari. Fin troppo semplice, non credete?
Infatti ci tocca complicare un po’ le cose ed adesso vediamo insieme il perché.
Con i due metodi precedenti abbiamo interrogato un webservice e ricevuto un JSON contenente una lista di contatti e, una volta ricevuta tale lista, abbiamo inserito in un array tanti oggetti NSDictionary quanti sono i contatti ricevuti. Ma l’oggetto NSDictionary è un tipo generico non è una nostra classe il che porta (magari non in questo esempio, ma di sicuro nella vita reale) ad avere diversi problemi durante la stesura del progetto. Vediamo quali sono i pregi derivanti dall’utilizzo di una classe:
- le variabili di istanza hanno dei nomi fissi che possiamo controllare nell’header della classe
- le variabili di istanza possono essere incapsulate dai metodi get e set
- Il nostro codice sarebbe più facile da leggere perché un oggetto di tipo Contatto è più identificabile di un generico NSDictionary
- Possiamo aggiungere metodi specifici che non sono previsti in un NSDictionary
- …la lista potrebbe continuare…
Sperando di avervi convinto creiamo subito la classe “Contatto” (file->new file->NSObject subclass) che ha semplicemente 4 proprietà di tipo NSString, non credo ci sia bisogno di particolari istruzioni, qui c’è il codice completo:
Questo è il file Contatto.h
#import
@interface Contatto : NSObject
@property (strong, nonatomic) NSString *nome;
@property (strong, nonatomic) NSString *cognome;
@property (strong, nonatomic) NSString *dataNascita;
@property (strong, nonatomic) NSString *sesso;
@end
e questo è il file Contatto.m
#import "Contatto.h"
@implementation Contatto
@synthesize nome,cognome,dataNascita,sesso;
@end
Creata la nostra classe possiamo aggiungere un #import Contatto in cima al file MainTableViewController.h e modificare il metodo fetchedData: in questo modo:
- (void)fetchedData:(NSData *)responseData {
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions error:nil];
NSMutableArray *contattiTMP = [[NSMutableArray alloc] initWithCapacity:[json count]]; //2
for (NSDictionary *dict in json) { //3
Contatto *c = [[Contatto alloc] init]; //4
c.nome = [dict objectForKey:@"nome"];
c.cognome = [dict objectForKey:@"cognome"];
c.dataNascita = [dict objectForKey:@"datanascita"];
c.sesso = [dict objectForKey:@"sesso"];
[contattiTMP addObject:c]; //5
}
//mi assicuro che l'array contatti non possa essere modificato.
self.contatti = [contattiTMP copy]; //6
[self.tableView reloadData];
}
- Il parser dell’oggetto responseData è rimasto uguale al precedente, quindi nessun cambiamento
- Dichiariamo e inizializziamo un NSMutablearray, ci servirà per memorizzare le istanze della classe Contatti
- Eseguo un ciclo for su tutti gli oggetti dell’array restituito dal parser JSON
- Per ogni iterazione creo un nuovo oggetto di tipo Contatto e ne imposto le proprietà leggendole dal dizionario.
- Infine aggiungo il Contatto all’array
- Terminata la procedura di creazione dei contatti assegno alla variabile di istanza contatti una copia dell’NSMutableArray creato al punto 2, questo perché ho scelto che tale variabile sia immutabile e quindi non voglio assegnargli un NSMutableArray.
Passiamo ora ai metodi relativi alla tabella:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [contatti count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [[contatti objectAtIndex:indexPath.row] nome];
// Configure the cell...
return cell;
}
e lanciamo l’applicazione. Il risultato sarà questo:

La gestione della tabella è già stata trattata in molti altri articoli, ed in questo caso non presenta nessuna particolarità, se avete dei dubbi non esitate a chiedere.
Passiamo alla visualizzazione del dettaglio. Vogliamo fare in modo che cliccando su una cella “Mario” vengano visualizzati i dati dell’utente “Mario”. Se avete seguito correttamente la parte di questo articolo relativa alla costruzione dello storyboard dovreste già poter cliccare sulla cella e vedere il viewcontroller di dettaglio, che però è vuoto. Vuoto perché nessuno gli ha detto che dati visualizzare!
Il metodo che dobbiamo implementare per avere il controllo del viewcontroller di dettaglio è questo:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; //1
Contatto *c = [self.contatti objectAtIndex:indexPath.row]; //2
DetailViewController *dvc = (DetailViewController *)[segue destinationViewController]; //3
}
- Otteniamo l’indexpath della cella che è stata selezionata
- Recuperiamo l’oggetto Contatto dall’array usando l’indexPath
- Recuperiamo l’istanza del viewcontroller di dettaglio usando il metodo destinationViewController
A questo punto abbiamo il riferimento al viewControlle di dettaglio ed un approccio “poco lungimirante” (eufemismo) potrebbe essere quello di impostare direttamente il valore delle textField con i valori prelevati dall’oggetto Contatto… Questo non è un buon approccio perché nell’ottica di separare quanto è possibile logiche e responsabilità dobbiamo prevedere la possibilità che DetailViewController venga modificato, per esempio, usando una webView piuttosto che quattro textField, se usassimo l’approccio “poco lungimirante” ciascuna modifica, anche minima, alla classe DetailViewController dovrebbe propagarsi anche alla classe MainTableViewController e di sicuro non è quello che vogliamo (in inglese di parla di “coupling” e “de-coupling” spero di aver dato l’idea del loro significato).
In questo caso quindi che facciamo? Basta ragionare un’attimo sullo scopo principale per il quale abbiamo creato la classe DetailViewController, che è quello di visualizzare i dettagli di uno specifico Contatto.
Allora di cosa ha bisogno per poter assolvere al suo compito? Beh, a bisogno che qualcuno gli dica quale contatto visualizzare, no?
Quindi modifichiamo il metodo precedente aggiungendo proprio il passaggio dell’oggetto Contatto:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
Contatto *c = [self.contatti objectAtIndex:indexPath.row];
DetailViewController *dvc = (DetailViewController *)[segue destinationViewController];
[dvc setContatto:c]; //4
}
Al punto 4 vi darà errore perché ancora la classe DetailViewController non ha alcun metodo setContatto. Lo aggiungeremo adesso.
Selezioniamo il file DetailViewController.h aggiungiamo #import “Contatto.h” in cima al file e una property di tipo Contatto:
@property (strong, nonatomic) Contatto *contatto;
Nel file DetailViewController.m non dimentichiamoci di aggiungere @syntetize contatto.
Possiamo ora modificare il metodo viewdidLoad in modo da visualizzare correttamente i dettagli del contatto:
- (void)viewDidLoad
{
self.nome.text = contatto.nome;
self.cognome.text = contatto.cognome;
self.datanascita.text = contatto.dataNascita;
self.sesso.text = contatto.sesso;
[super viewDidLoad];
}
Ammiriamo finalmente il nostro programma in tutto il suo splendore! 🙂

E adesso?
Se avete seguito per intero questo lungo tutorial avrete notato che abbiamo messo veramente tanta carne al fuoco, quindi sta a voi capire che cosa approfondire.
Se vi interessa la parte web potreste trovare utile approfondire il php (Corso php w3c) o perché no uno dei tanti framework per lo sviluppo in questo linguaggio come simfony o codeigniter.
Questi framework utilizzano un’approccio diverso al database rispetto all’esempio qui proposto, ma un buon programmatore non può esimersi dal conoscere almeno un pò il linguaggio SQL (Corso SQL w3c).
Se invece siete più interessati alla parte iOS date un’occhiata a questo articolo (JSON Benchmark) in cui viene eseguito un benchmark sui vari framework per effettuare il parsing di un JSON, purtroppo scopriremo che il metodo usato qui non è il più veloce in assoluto (anche se si guadagna un onorevole secondo posto).
Non mi resta che darvi il link del progetto completo, lo trovate su github a questo indirizzo: JSClient ed augurare a tutti buona programmazione!









86 Responses to “T#106 – JSON e iOS 5: creiamo il client iPhone per il nostro web service PHP (Parte 2)”
19 Gennaio 2012
StefanoGrazie mille, oggi provo a realizzare il tutto! Chiedo troppo lo so, ma mica hai in programma una Parte 3? Qualcosa dove andiamo a modificare i dati dell’utente sul db inviando la richiesta codificata JSON e ricevendo la risposta sempre codificata in JSON tipo
{"success": true, "message":"Record salvato correttamente.", "dati":{"nome":"Mario", "Cognome":"Rossi" ...}}Ciao e grazie ancora, tutorial utilissimo per me!
20 Gennaio 2012
lucaComplimenti per l’articolo.. una domanda stupida.. se ricevo parametri vuoti dal json =>
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
..come posso gestirlo secondo voi?
L’errore dovrebbe essere lanciato quà:
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions error:nil];
20 Gennaio 2012
luca.. come non detto!! .. era il nome dell’url errato 🙂
25 Gennaio 2012
FlavioCiao, complimenti per l’articolo (parte 1 e parte 2) che ho implementato e funziona….fino ad un certo punto.
Premetto che ho un server scritto in Delphi che mi ritorna oggetti JSon.
Nel server sono implementate 2 funzioni: la prima mi ritorna un oggetto JSonObject la cui struttura è analoga a quella utilizzata nell’esempio dell’articolo: {“result”:{“Articolo”:PASTA KG.1″,”Giacenza”:”12″}}; seguendo l’esempio dell’articolo funziona.
La seconda mi restituisce un JSonArray: {“result”:[{“Articolo”:”FERRERO K. BUENO WHITE GR.43″,”Giacenza”:”180″},{“Articolo”:”S.CARLO PATATINA GR.180 CLASSICA”,”Giacenza”:”64″},{“Articolo”:”FERRERO KINDER BUENO GR.43″,”Giacenza”:”180″}]};
E’ proprio la lettura di questa struttura che non riesco a leggere.
Un aiuto?
Grazie mille!!!
25 Gennaio 2012
Ignaziocche errore ti da? riesci ad ottenere il dizionario con l’array?
25 Gennaio 2012
FabioCiao complimenti per l’articolo davvero interessante. Ho visto dall’articolo che vengono eseguite chiamate al server in GET e possibile eseguirle anche in POST ad esempio per il passaggio di user e pwd ?
grazie mille
25 Gennaio 2012
Ignaziocovviamente si, il tipo di comunicazione utilizzato tra client e server può essere in get in post o con un piccione viaggiatore 😉
26 Gennaio 2012
Fabio… non sareste cosi gentile da darmi un incipit su come fare una chiamata post …è tre giorni che ci sbatto la testa 🙁
26 Gennaio 2012
ignazioccerto! questa libreria fa al caso tuo:
http://allseeing-i.com/ASIHTTPRequest/How-to-use#sending_a_form_post_with_ASIFormDataRequest
considera però che sta diventando ogni giorno più “vecchia” perché sono nate altre librerie simili più leggere di questa qui…come AFNetwork.
26 Gennaio 2012
FlavioCiao,
il codice che sto cercando di far funzionare è questo:
NSArray* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
NSMutableArray* MyGiacenze =[[NSMutableArray alloc] initWithCapacity:[json count]];
NSDictionary *myres = [json objectAtIndex:1];
Giacenze *tmpgiac = [[Giacenze alloc] init];
tmpgiac.articolo = [json objectAtIndex:0];
[MyGiacenze addObject:tmpgiac];
contatti= [json copy];
[self.tableView reloadData];
Non so dirti esattamente che tipo di errore mi da, ma ho un SIGAbort nel main dell’applicazione.
26 Gennaio 2012
FlavioRecap:
premesso che nel mio post precedente, ho incollato il codice sbagliato, il mio problema l’ho risolto.
Ecco il codice:
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
NSArray* myobject = [json objectForKey:@"result"];
NSArray* aDict = [myobject objectAtIndex:0];
NSMutableArray* MyGiacenze =[[NSMutableArray alloc] initWithCapacity:[aDict count]];
for (int M=0; M < [aDict count]; M++)
{
Giacenze *tmpgiac = [[Giacenze alloc] init];
tmpgiac.articolo = [[aDict objectAtIndex:M] objectForKey:@"Articolo"];
[MyGiacenze addObject:tmpgiac];
}
contatti = [MyGiacenze copy];
[self.tableView reloadData];
29 Gennaio 2012
FabioGrazie mille .
Ho notato però che non è possibile gestire la libreria con ARC. E possibile ,se ha senso, disibilitare la compilazione per questa libreria ( NO ARC )
grazio
29 Gennaio 2012
ignazioca quale libreria ti riferisci?
29 Gennaio 2012
FabioHo provato con questa:
http://allseeing-i.com/ASIHTTPRequest/How-to-use#sending_a_form_post_with_ASIFormDataRequest
ma non supporta ARC
non so se ne esistano altre per che supportino ARC .
grazie
Fabio
29 Gennaio 2012
ignaziocah, scusa non avevo letto il nick. Puoi usare ugualmente asihttp però devi mettere una impostazione per ciascun file della libreria…non so se su github trovi qualche fork con questa modifica già fatta. Sembra che AFNetwork (https://github.com/AFNetworking/AFNetworking) sia un po’ più avanti in questo senso.
1 Febbraio 2012
GiulioScusa io ho un problema.
Il metodo “prepareforSegue” NON viene proprio eseguito.
Sono andato in debug e ho controllato che non viene mai eseguito.
A cosa può essere dovuto?
Grazie.
1 Febbraio 2012
MatteoCiao a tutti, ottimo tutorial!!
Purtroppo ho un problema:
NSArray* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions error:nil];
non mi da nessun risultato, il json è vuoto!
Potete aiutarmi?
Grazie
1 Febbraio 2012
MatteoRisolto ! era “sporco” il file php…
4 Febbraio 2012
SteCiao,
grazie per il tutorial,
saresti così gentile da fare un video su questo tutorial? Sono all’inizio e a metà mi sono perso. Soprattutto nella parte in cui dici: “Anche in questo caso abbiamo usato un generico viewController, ma in realtà ci servirà uno specifico viewController, aggiungiamolo quindi da file->new file e poi modifichiamo lo storyboard affinché rispecchi la nuova classe, allo stesso modo di come abbiamo fatto poco fa con il MainTableViewController.
Ci serviranno 4 textField per visualizzare i dettagli del contatto selezionato e per fare ciò sfruttiamo una comoda funzionalità del nuovo XCode, apriamo lo storiboard e trasciniamo 4 textfield sul viewcontroller, selezioniamo la visualizzazione dell’assistant editor e trasciniamo dalle textfield verso l’intestazione della classe:”. Dal momento che non hai inserito gli screenshots dettagliati di questo passaggio non ho ben capito in realtà come i vari passaggi. Soprattutto quando chiedi di creare determinate classi che non vedo come tipologia nella finestra per creare nuovi file. Fino al paragrafo precedente tutto ok.. Grazie
9 Febbraio 2012
StefanoSalve, e grazie mille degli ottimi tutorial, ho una domanda, funziona tutto, però adesso ho un dubbio, come faccio ad esportare il tutto, cioè se io sviluppo un app che sfrutta il sistema spiegato per creare prima una lista dei contatti e poi una view con le loro caratteristiche come faccio a presentarla ad itunes? mi spiego meglio il database che risiede su localhost dove lo devo mettere e anche le autenticazioni per accedervi come le devo cambiare?
Grazie mille.
9 Febbraio 2012
VetranksSalve e grazie del magnifico tutorial, volevo chiedere, come faccio a metterci un cerca cio è una search bar e come devo modificare il codice?
Grazie mille
7 Marzo 2012
giovanniho creato il webserver rest seguendo la guida precedente, e ho messo l’indirizzo nel progetto completo scaricato da qui ma mi da errore…
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
Thread 1 SIGABRT
18 Marzo 2012
GiuseppeInnanzitutto ottima guida, complimenti però come posso controllare all’avvio dell’app la connessione ad internet? Perché altrimenti l’applicazione non parte. Qualcuno mi può aiutare? Grazie
5 Aprile 2012
AlessioCiao ragazzi, ottimo ed utilissimo tutoria. Tutto è andato alla perfezione, e l’app funziona benissimo.
Ora però volevo chiedervi come faccio ad inserire una search bar and search display controller alla lista dei dati JSON??
io sul vostro blog ho trovato anche questo tutoria, ma non funziona
http://www.devapp.it/wordpress/t041-usiamo-le-uitableview-parte-3-implementiamo-la-barra-di-ricerca.html
Chi mi sa aiutare?
GRAZIE MILLE
11 Aprile 2012
MaryI tutorial del sito sono sempre esaustivi, ma questo proprio non sono riuscita a seguirlo…dunque, proporrei un video di questo tutorial se fosse possibile,
grazie anticipatamente.
19 Aprile 2012
MaryBene, anzi benissimo…ce l’ho fatta alla fine ed era quello che mi serviva…
23 Aprile 2012
FulvioComplimenti questo tutorial mi è stato utilissimo…!
15 Maggio 2012
GianniSalve e complimenti per il tutorial, ho eseguito tutti i passaggi e tutto ok.
Ho solo un problema, se in uno dei campi del database c’è una lettera accentata, es è à ecc.. l’applicazione va in tilt..
Perche? grazie ancora
15 Maggio 2012
Ignaziocin che senso? nel senso che ti arriva una stringa con caratteri strani? devi verificare che la collation del tuo database sia corretta perché dipende come l’hai creato non sono ammessi caratteri utf-8
17 Maggio 2012
GianniGrazie per avermi risposto
No questo è quello che succedeva : es Nome Marì
risultato Nome NULL
e sul similatore se qualche campo aveva caratteri tipo èàé l’app si chiudeva.
Ho risolto così:
$contatti[$j]->setNome(utf8_encode ($row[1])); ecc..
adesso accetta qualsiasi cosa e non si blocca
Grazie ancora buona serata
21 Maggio 2012
iCreilciao anke io ho un problema volevo caricare i punti che mi ridava indietro con un file json googlemaps solo ke quando vado a fare
NSArray* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
non mi crea un array ma bensì una stringa…se vado a fare nslog x vedere cosa contiene mi rida paro paro il json ke ho caricato…sapete dirmi xk?
22 Maggio 2012
Ignaziocpiuttosto strano, sicuro che la url che utilizzi restituisca un JSON?
se è una URL pubblica prova a postarla qui che vediamo dove sta il problema.
10 Giugno 2012
GiuseppeCiao, complimenti per l’ottima guida. Volevo sapere se era possibile utilizzare questo database anche offline. E’ possibile? Grazie
10 Giugno 2012
ignaziocin che senso? l’articolo spiega come fare richeiste ad un server e ottenere risposte in JSON se sei offline non puoi fare nessuna richiesta.
12 Giugno 2012
ByterosInnanzitutto complimentoni!!!
Domandina…
Se il mio file.php contenesse una query di inserimento, che metodo dovrei usare per inviare dati al database, anziché riceverli? (vorrei evitare librerie esterne se possibile).
Credo sia una domandona la mia, forse richiederebbe una parte 3 di questo tutorial.
Grazie in anticipo.
30 Giugno 2012
LucaOttimo tutorial,
ho un unico problema.
Se eseguo la query dal web server, mi viene restituito il json valorizzato,
mentre dal programma ottengo solo una tabella vuota.
Non riesco a capire dove possa essere l’errore……
2 Luglio 2012
ignaziocbeh i problemi possono essere tantissimi, prova a postare sul forum un pò di codice.
2 Luglio 2012
Lucahttp://forum.devapp.it/showthread.php?4621-Problema-con-JSON/page3
Ho postato il codice in questa discussione, ma non ne siamo ancora venuti a capo….
3 Luglio 2012
ignaziocvedo che hai risolto, bene.
5 Luglio 2012
jonnyCiao, sto cercando di inserire una search display controller.Ho seguito lo schema che si trova nella guida Tutorial pratici per iOS SDK v2.1.pdf, ma ho problemi in questo metodo
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
NSLog (@" prima Number of elements in array = %u", [Objectslisttrue count]);
[Objectslisttrue removeAllObjects];
NSString *elemento;
int intero=0;
NSUInteger conta= intero;
//NSNumber *contaa= [NSNumber numberWithInt: 0];
for ( elemento in [contatti mutableArrayValueForKey:@"nome"] ){
NSLog(@"2 ");
NSComparisonResult result = [elemento compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
NSLog(@"sono qui è tutto ok");
// controlliamo se l'elemento corrisponde alla stringa di ricerca
if (result == NSOrderedSame){
NSLog(@"55");
NSLog(@"59");
[Objectslisttrue insertObject:elemento atIndex:conta];
NSLog (@" dopod Number of elements in array = %u", [Objectslisttrue count]);
NSLog(@"%@",Objectslisttrue);
}
}intero++;
}
mi trova l’elemento ma non ha link per aprire la pagine di dettaglio. Mi potresti dare una mano.grazie
5 Luglio 2012
jonnyCiao, mi sembrava di aver fatto passi avanti ma non funziona lo stesso. In un sito ho visto una cosa un pò simile e mi sono ispirato a questo link anche se loro utilizzano solo uisearch bar.
la parte che ho modificato è
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{/*
Update the filtered array based on the search text and scope.
*/
[self.Objectslisttrue removeAllObjects];// First clear the filtered array.
NSLog (@" prima Number of elements in array = %u", [Objectslisttrue count]);
/*
Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array.
*/
for (Contatto *c in contatti)
{
NSLog(@"51");
NSLog(@"52");
NSComparisonResult result = [c.nome compare:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch) range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame)
{
NSLog(@"53");
[self.Objectslisttrue addObject:c];
NSLog (@" dopo Number of elements in array = %u", [Objectslisttrue count]);
}
}
}
Ho trovato poi nel debug questo errore
-[Contatto isEqualToString:]: unrecognized selector sent to instance 0x8196f10
2012-07-05 13:08:50.856 Jonny'sApp[6079:16403] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Contatto isEqualToString:]: unrecognized selector sent to instance 0x8196f10'
5 Luglio 2012
Ignaziocti consiglio di scrivere sul forum, c’è anche una nuova sezione proprio per discutere degli articoli.
L’implementazione della seach bar non è legata a json, quindi se hai capito il meccanismo puoi usare uno dei tanti tuorial che trovi in giro.
13 Luglio 2012
MarcoScusate la domanda ma sono alle prime armi. Uso xcode 4.2 e seguendo il tutorial per filo e per segno quando arrivo alla fine della prima metà, ottengo correttamente la lista dei nomi (Luigi, Franco ecc.) ma quando vado a cliccare per andare sul dettaglio non succede assolutamente nulla: la cella risulta cliccata ma nessun effetto. Grazie
13 Agosto 2012
mezzsalve, nella mia app, ma anche da quella che ho scaricato da github, mi dice Thread 1: signal SIGABRT e mi seleziona @autoreleasepool
6 Settembre 2012
AstCiao a tutti e ovviamente complimenti per il vostro lavoro.
ho fatto tutto e funziona perfettamente, anzi l’ho un po ingrandito inserendo un’altra table view prima che filtra i risultati della seconda tableview.
ora mi trovo di fronte a un problema stupido:
nella seconda table view dovrei passare un parametro alla url del json…
in poche parole dovrei fare una cosa del genere:
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.server.it/pagina.php?parametro=" + parametro che viene dal segue ]];
ma in questo linguaggio ancora un po ostico per me non ho ancora capito come posso farlo! mi dareste una mano?
grazie ast
10 Settembre 2012
AstNessun suggerimento??
10 Settembre 2012
Aststo provando a fare così, ma non funziona, sebbene il compilatore non mi dia errori poi sembra non passare nulla alla url, e quindi va tutto in crash al tocco della riga:
NSString *miaTipologia = @"3";
NSString *urlConcatenata = [NSString stringWithFormat:@"http://localhost/miaApp/jsonRisposta.asp&tipologia=%@", miaTipologia];
[super viewDidLoad];
searchBar.delegate = (id)self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlConcatenata]];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES]; });
dove diavolo sbaglio!!!
10 Settembre 2012
FedericoCiao a tutti!! tutorial grandioso, sto implementando la prima app grazie a voi!!
una domanda, secondo voi dove posso inserire le chiamate a MBProgressHUD per settare la percentuale di caricamento?
Nella fetchdata non ha senso perché l’operazione è talmente immediata che si carica subito… la parte lenta è sicuramente questa
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@”http://localhost:8888″]];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES]; });
ma non so assolutamente dove infilare il HUD.progress = progress, dato che non so come capire a che punto sono del download! qualcuno ha suggerimenti? grazie
10 Settembre 2012
Astok …risolto…
in effetti era giusto, sbagliavo la url statica…
a chi dovesse servire ecco il codice corretto:
NSString *miaTipologia = tipologiez.idTipo; // l'id che mi arriva dal precedente tableview
NSString *urlConcatenata = [NSString stringWithFormat:@"http://localhost:8080/recipesApp/jsonRicette.asp?tipologia=%@", miaTipologia];
searchBar.delegate = (id)self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlConcatenata]];
[self performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES]; });
12 Settembre 2012
ignaziocin questo esempio è stato utilizzato il metodo dataWithContentsOfURL che è sincrono e non ha quindi callback dove settare la percentuale.