
Qualche settimana fa ho avuto modo di partecipare al meeting di #pragma mark ed ascoltare l’interessante presentazione di Massimo Oliviero intitolata “Building iOS App Project & Architecture” e mi è venuta l’idea di scrivere questo articolo.
Tutti noi usiamo quotidianamente Xcode, ma un po’ per prigrizia e un po’ per oggettiva complessità del programma, molto spesso ci limitamo ad usare le funzionalità principali, trascurando invece funzionalità che in alcuni casi posso renderci la vita più semplice.
Gestione del filesystem
Diciamoci la verità, se c’è un punto dolente su Xcode è proprio la sua gestione del filesystem. Per quanto il progetto possa apparire ordinato, con tanto di gruppi e sottogruppi in realtà è solo un’illusione 😉 perché per impostazione predefinita Xcode piazza tutti i file nella stessa directory, e la nostra reazione quando lo scopriamo è più o meno questa:

Durante il talk di Massimo ho scoperto di non essere l’unico ossessivo-compulsivo sulla struttura delle cartelle e putroppo Xcode non ci rende la vita facile. Se volete ottenere una struttura ordinata sul filesystem il primo consiglio è quello di partire fin da subito con il piede giusto, perché una volta che i file sono aggiunti al progetto può non essere semplicissimo spostarli. Per esempio, personalmente prima di aggiungere una nuova classe al progetto creo sempre prima la cartella per ospitarla ed il modo più veloce di farlo è cliccare con il tasto destro su una cartella già presente sul nostro progetto e selezionare “Add files to…”

Nella finestra di selezione del file cliccare sul tasto “New folder”

e infine selezionare “Add”. In questo modo avremo creato una cartella sul filesystem e un gruppo all’interno del progetto e questi saranno linkati, cosicché tutti i file che creeremo dentro questo gruppo saranno creati dentro questa cartella.
Per quanto riguarda le immagini trovo invece molto comoda la funzionalità di “folder reference” anche se devo dire che non è molto usata. Quando trascinate su Xcode la vostra catella con le immagini, invece di selezionare “Create group for any added folder” selezionate “Create folder references for any added folder”, così come si vede nell’immagine qui di seguito:

In questo modo Xcode creerà un particolare gruppo, riconoscibile dal colore azzurro, che è in realtà un riferimento alla cartella sul filesystem. A differenza del gruppo creato precedentemente, in questo caso ci basterà aggiungere un file all’interno della cartella e questo verrà automaticamente reso disponibile all’interno di Xcode.

I Folder reference sono mantenuti anche all’interno del progretto compilato, a differeza dei gruppi tradizionali che vengono poi “appiatti” durante la compilazione. Questo comporta però una notevolte differenza nella gestione dei file perché bisognerà tenere conto della presenza di questa folder, ad esempio per caricare l’immagine bisognerà scrivere
UIImage *img = [UIImage imageNamed:@"images/test.png"];
Esiste anche una terza (e ancora meno usata) tecnica che consiste nell’usare i Bundle. Un bundle non è altro che una cartella rinominata opportunamente con estensione *.bundle
La comodità di utilizzo di un bundle è che possono essere trattati come dei normali file e quindi se vi capita di dover distribuire delle risorse è più comodo distribuire un unico file .bundle invece che una folder con i file, infatti è comune trovarli insieme ai framework.
Per accedere programmaticamente al contenuto di un bundle bisogna prima ottenere un riferimento al bundle e successivamente si può ricavare il percorso del file
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"images" ofType:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
NSString *filePath = [bundle pathForResource:@"test" ofType:@"png"];
Un progetto, più versioni
Questo argomento è stato trattato spesso anche sul nostro forum, la domanda in genere è:
Devo realizzare due progetti identici, uno lite e uno pro. Devo fare una copia di tutto?
Neanche a dirlo, la risposta è ovviamente no! La duplicazione del codice è da evitare a tutti i livelli, mai avere due metodi che hanno lo stesso scopo, o due classi… o perfino due progetti.
Esistono due metodi per risolvere in modo elegante questo problema: il primo è creare più target, il secondo più configurazioni. Vediamo in dettaglio.
Ciascun progetto xcode può avere più target, in Xcode 5 ne vengono creati di default due, il primo è il target legato alla nostra applicazione iOS, mentre il secondo è legato ai test (vedi qui)
Per creare un nuovo target possiamo duplicare uno dei target esistenti

oppure crearne uno ex-novo cliccando sull’opzione “Add Target…” e selezionando il tipo di target desiderato.
Utilizzare più target offre il maggior livello di versatilità, ma anche di complessità, infatti sarebbe tecnicamente possibile creare anche applicazioni totalmente differenti a partire dalla stesso progetto, ma con differenti target. L’utilizzo più tipico è però quello in cui bisogna generare due applicazioni diverse che condividono la gran parte del codice, come ad esempio la versione iPad e la versione iPhone della stessa applicazione. Creando un nuovo target avremo un nuovo file info.plist dove specificare le caratteristiche del progetto, avremo i nuovi scheme per la compilazione e soprattutto avremo modo di specificare ciascun file a quali target appartiene

La creazione di più configurazioni è differente rispetto alla creazione di più target ed è indicata quando si vuole compilare il progetto con alcune piccole varianti, come ad esempio la versione “pro” e la versione “lite” dello stesso progetto, oppure una versione con delle modifiche grafiche.
Per creare una nuova configurazione selezionare il progetto, quindi, dalla tab “info”, cliccare sul pulsante “+” per duplicare una delle configurazioni attuali.

Una volta create le configurazioni necessarie potremo andare a specificare le opzioni di compilazione per la specifica configurazione, così come siamo già abituati a fare per “debug” e “release”

La sezione di una configurazione al posto di un’altra avviene attraverso lo scheme. Cliccando su “Manage scheme” e successivamente doppio click sul nome dello scheme che vogliamo modificare, si accede alla schermata di gestione dello scheme.

per ciascuna delle sei tipologie di compilazione è possibile definire quale configurazione utilizzare

L’opzione più semplice è quindi quella di creare un nuovo scheme e per il nuovo scheme selezionare le nuove configurazioni, così quando vorremo cambiare configurazione sarà sufficiente buildare lo scheme corrispondente. Nel mio esempio ho creato dei file di configurazione per buildare una “red version” cioè una versione che ha delle piccole varianti grafiche. Ho creato quindi uno scheme “SampleApp_redVersion” ed ho configurato lo scheme per usare i nuovi file di configurazione.
Fin qui abbiamo creato le configurazioni, gli scheme, possiamo cambiare i settings ma non abbiamo visto nulla per identificare la versione in modo programmatico. Anche in questo caso gli approcci sono due, le variabili d’ambiente e le macro per il preprocessore.
Per definire una variabile d’ambiente selezionare la tab “Arguments” dalla schermata di gestione degli scheme e aggiungere una variabile tramite il tasto “+”

Il valore di questa variabile sarà accessibile via codice tramite la classe NSProcessiInfo
[[[NSProcessInfo processInfo] environment] objectForKey:@"REDV"];
L’utilizzo delle macro di preprocessore è un po’ diverso e permette di escludere dalla compilazione intere parti di codice e questo spesso può rivelarsi molto utile.
Per definire una nuova macro accedere ai settings del progetto e trovare la voce “Preprocessor macros”. Aprire il selettore e definire la nuova macro per le configurazioni desiderate, la macro è nella forma nomemacro=valore

Per verificare via codice il valore di questa macro bisognerà utilizzare i comandi del preprocessore, in particolare potremo scrivere:
#if REDV == 1
self.titleLbl.text = @"Red Version";
self.sampleView.backgroundColor = [UIColor redColor];
#endif
La particolarità in questo caso è che se REDV non è dichiarata o non vale 1, le due righe di codice non vengono totalmente prese in considerazione perché rimosse in fase di preprocessing.
Gestire il numero di versione
Spesso si vuol automatizzare l’incremento del numero di build del progetto e in rete si trovano diversi script per farlo e tutti più o meno si basano sul comando PlistBuddy che serve per intervenire direttamente sui file plist del nostro progetto. Pochi sanno che Apple fornisce un tool apposito per fare questo lavoro che si chiama agvtool. Per utilizzarlo dobbiamo soltanto configurare correttamente il progetto inserendo tra le opzioni il numero attuale di versione e la volontà di utilizzare il tool di versioning di Apple. La configurazione corretta è visibile in questa immagine

Una volta che avremo configurato il progetto per incrementare il numero di build avviare un terminale e, posizionandosi nella directory del progetto, digitare:
agvtool bump -all
In questo modo verrà incrementato il numero di build e verrà memorizzato nel file plist del progetto.
Ovviamente l’utilità di questo comando è limitata soltanto a chi vuole automatizzare il processo di archiviazione e distribuzione, per esempio potrebbe essere una buona idea inserirlo in uno script hook di git o in uno script di generazione del file *.ipa per la distribuzione ad-hoc.
Un pluging to bring them all
Le funzionalità offerte da Xcode possono essere estese tramite tutta una serie di plugin sviluppati appositamente per semplificarci il lavoro. Purtroppo non esistono API ufficiali per lo sviluppo di questi plugin quindi il loro numero è molto più esiguo di quello che potrebbe essere in realtà. Tra i plugin che trovo più utili vi segnalo:
- ColorSense (https://github.com/omz/Colorsense-for-Xcode) un plugin per rendere più facile la digitazione di un colore all’interno del codice (qui un video)
- Uncrustify (https://github.com/benoitsan/BBUncrustifyPlugin-Xcode) per me che sono un fanatico dell’indentazione del codice è stato una manna dal cielo, rende disponibile il comando uncrustify per formattare il codice direttamente da una voce di menù.
- ImageNamed (https://github.com/ksuther/KSImageNamed-Xcode) questo forse è stato il primo plugin reso disponibile, facilita di molto il caricamento delle immagini con il metodo
imageWithName:
perché durante la digitazione visualizza un’anteprima dell’immagine.

Esiste poi un tool che si chiama Alcatraz (http://mneorr.github.io/Alcatraz/) che ha ispirato il titolo di questa sezione, ovvero un plugin che ci permette in modo semplice di installare/disinstallare tutti gli altri plugin. L’installazione è semplice in maniera vergognosa e con un semplice click si possono installare molti plugin utilissimi e tantissimi schemi di colore. Purtroppo l’unica pecca è che attualmente il supporto con Xcode5 non è totale. Sul mio mac ho sia Xcode 4.6.3 che 5.1 e installando Alcatraz riesco ad avviarlo soltanto da Xcode 4.6.3, tuttavia alcuni plugin installati funzionano successivamente anche con la versione 5.1
Sicuramente l’integrazione avverrà a brevissimo, quindi tenetevi pronti 😉
Alla prossima e buona programmazione!
4 Responses to “Xcode Tips & Tricks: Gestione del filesystem, un progetto più versioni, plugin”
12 Novembre 2013
neronorxOttimo articolo,ci voleva proprio!!
In effetti mi ha sempre dato fastidio di come xcode mettesse tutti i file in una sola cartella a c…zi suoi!
Metto questo articolo come bookmark.
Bravo
12 Novembre 2013
neronorxP.s.
Quello del disegno sul mac sono io! 😀 quando mi hai fotografato???? 😀 😀 😀
12 Novembre 2013
Ignaziocdiciamo che questo articolo va di pari passo con quest’atro qui: http://www.devapp.it/wordpress/usare-xcode-senza-utilizzare-il-mouse-o-quasi.html
13 Novembre 2013
LucaComplimenti Ignazio…. un articolo molto utile… Grazie.