Da Java e Android a Objective C e iOS andata e ritorno – parte II

Nella prima parte di questo mini viaggio abbiamo visto un confronto fra gli ambienti di sviluppo, i componenti e i simulatori/emulatori utilizzabili per sviluppare per Android e iOS. In questo post parliamo di una delle cose più importanti (sembrerà strano ma è così :)) quando si scrive codice: il linguaggio di programmazione!

Objective C vs Java

Da profano prima di questa avventura avevo pensato:

Objective C è una estensione del C, io conosco java, conosco un po’ di C e C++ che ci vorrà a imparare Objective C! Ho imparato l’ereditarietà in JavaScript non mi spaventa più niente!

Ok, Objective C è una estensione del C ma del C che siamo abituati a vedere c’è proprio poco: le parentesi graffe, il punto e virgola, i tipi primitivi, l’if e il while. Vedendo un listato di codice Objective C ho avuto la stessa impressione che ho avuto a suo tempo davanti a una regular expression bella incasinata! Per capirsi per creare un oggetto Persona passando nome e cognome è necessario scrivere questo codice:

Persona *p = [[Persona alloc] initWithSurname: @"Rossi" name: @"Mario"];

A prima vista si notano almeno tre cose che mi hanno fatto impazzire:

  1. per creare una stringa è necessario usare una @, ok dopo un po’ ci si fa l’abitudine;
  2. per invocare un metodo su un oggetto non si usa la notazione oggetto.metodo(parametro) o oggetto->metodo(parametro) ma [oggetto metodo: parametro]. Questa notazione è dura da digerire per chi non l’ha mai vista soprattutto nel caso di chiamate a più metodi in cascata…;
  3. nel caso di metodi con più di un parametro tutti i parametri hanno una label (nell’esempio name: è la label del secondo parametro). Questa cosa può essere comoda visto che per simulare un comportamento analogo in Java è necessario scrivere un builder. Però all’inizio è dura entrare nel meccanismo e per scrivere ogni chiamata a un metodo c’è da pensarci per bene.

Una caratteristica interessante di Objective C (altrimenti sembro di parte) sono le property: invece di dover scrivere i getter e i setter basta scrivere un @synthesize. Quando si usa si può addirittura usare la notazione con il punto e scrivere persona.nome! Però i puristi non usano questa notazione con il punto, forse per non essere scambiati per javisti…

Linguaggi statici e dinamici

A prima vista Objective C potrebbe sembrare un linguaggio con typing statico, in realtà non lo è del tutto! Se si invoca un metodo che non esiste viene generato solo uno warning. Si potrebbe parlare per ore sulle differenze fra linguaggi statici e dinamici, ne ha parlato benissimo Paolo Perrotta in un talk a BetterSoftware, se avete tempo date un’occhiata al video. Personalmente faccio il tifo per quelli statici (qualcuno di voi forse l’aveva già intuito! :D). La comodità dell’autocomplete, di poter eseguire un refactoring e di sapere dove viene invocato un certo metodo (vi ricordate quei menu che mancano su Xcode?) non li baratterei mai con la possibilità di aggiungere metodi al volo e altre cose tipiche dei linguaggi non strong typed.

Una cosa che ancora non ho capito se amare o odiare è che nel caso di una chiamata di un metodo su un oggetto null (o nil come si definisce in Objective C) non succede niente, non viene lanciata nessuna eccezione. Può essere comodo per evitare di scrivere if di guardia, ma può rendere più complicata la fase di debug. Mettendo insieme questo e il fatto che Objective C non è strong typed si può eseguire tranquillamente una chiamata a un metodo non definito su un oggetto nil:

NSObject *obj = nil;
[obj metodoNonEsistente];

L’esecuzione di queste due righe di codice genera solo uno warning in compilazione, a runtime funziona tutto e non vengono sollevate eccezioni. Comodo? Dipende dai punti di vista!

Organizzazione delle classi: i package

I nomi delle classi in Objective C spesso iniziano con due lettere maiuscole, per esempio le classi che rappresentano stringhe e date sono rispettivamente NSString e NSDate. Queste due lettere identificano la libreria di appartenenza della classe, in questo caso NS sta per NeXTSTEP, sistema operativo sviluppato alla NeXT, azienda fondata da Steve Jobs nel periodo in cui non era alla Apple. Ma la domanda nasce spontanea: non potevano usare i package come nei linguaggi di programmazione moderni? La risposta è sconvolgente per chi ha sviluppato in un progetto con almeno 10 classi: non hanno usato i package perchè in Objective C non esistono! Per questo motivo è nata la comoda convenzione di mettere un prefisso di due caratteri che indica la libreria per evitare conflitti sui nomi…

Garbage collector C vs retain/release

Quando si inizia a sviluppare in Java (magari arrivando dal C/C++) una delle cose più affascinante è sicuramente il Garbage Collector. Niente più malloc e chiamate simili, niente più memory leak perchè pensa a tutto il Garbage Collector! L’entusiasmo iniziale svanisce quando si sviluppa lato server e c’è da capire come funziona il Garbage Collector nei dettagli perchè la ram non basta mai. A quel punto ci si imbatte in 1000 parametri da passare alla Java virtual machine, si scopre che il Garbage Collector blocca tutto e quello che sembrava una magia si trasforma in un incubo! 🙁

In Objective-C il Garbage Collector esiste ma solo se si sviluppa per Mac (e quindi non è utilizzabile su iOS). La gestione della memoria avviene in modo manuale, i due metodi fondamentali sono retain e release. Con retain si aumenta il retain count dell’oggetto, con release si diminuisce. Quando il retain count torna a zero la memoria viene automaticamente rilasciata. Semplice? Non troppo soprattutto quando si passano oggetti fra più metodi. Per aiutare lo sviluppatore è stato creato anche il metodo autorelease, invocando questo metodo in pratica l’oggetto sarà liberato al primo momento utile automaticamente. Questo argomento meriterebbe un post intero (o forse anche un libro!) e sicuramente non sono io la persona giusta per scriverlo…

A partire da iOS 5 è stato introdotto l’Automatic Reference Counting, se viene abilitato a livello di compilatore non c’è più bisogno di invocare manualmente retain e release. ARC è concettualmente diverso da un Garbage Collector: esegue un’analisi statica del codice e inserisce automaticamente retain e release dove necessario. Non so se i puristi dell’Objective-C usano questa feature, si potrebbe avere qualche byte che viene liberato con qualche millisecondo di ritardo e il sistema potrebbe perdere in reattività! 🙂

Insomma è utile il Garbage Collector o no? Secondo me la risposta è sicuramente si, c’è sicuramente una piccola perdita del controllo della memoria (il Garbage Collector parte più o meno quando vuole) ma il gioco vale sicuramente la candela.

Conclusioni

Siamo arrivati alla fine di questo viaggio, sono stato di parte? Un po’ si ma avrei potuto fare di peggio… Sicuramente iOS e Android sono due ottimi sistemi operativi, la diffusione e il numero di applicazioni sugli store parla da solo. Quale dei due è meglio usare? La risposta giusta ovviamente non esiste! L’unica cosa di cui sono convinto è che se conoscete Java per iniziare a sviluppare su Android non dovrete faticare troppo, dopo un bel corso di tre giorni sarete pronti a sviluppare la vostra prima applicazione (fine messaggio promozionale!). Non mi sento di dire la stessa cosa per gli sviluppatori C/C++, mi dispiace per voi ma passare a Objective-C non sarà così banale. E voi, avete fatto un viaggio simile? Sono l’unico che ha incontrato queste difficoltà?

Fabio Collini

Software Architect con esperienza su piattaforma J2EE e attualmente focalizzato principalmente in progetti di sviluppo di applicazioni Android. Attualmente sono in Nana Bianca dove mi occupo dello sviluppo di alcune app Android. Coautore della seconda edizione di Android Programmazione Avanzata e docente di corsi di sviluppo su piattaforma Android. Follow me on Twitter - LinkedIn profile

  • Stefano Gemma

    Solo una nota da programmatore C++ sulla Garbage Collection. Sebbene sia vero che de-allocare manualmente un oggetto al momento giusto potrebbe sembrare uno stress, è anche vero che, se ci si abitua a programmare bene e con metodo, non è poi così difficile mantenere un codice libero da memory leak o de-allocazioni multiple dlelo stesso oggetto. Spesso basta ricordarsi di scrivere la delete dei puntatori di oggetti allocati subito dopo avere scritto la corrispondente new (in C++ di solito si evita malloc). Se il puntatore è a livello di classe, appena scritta la sua dichiarazione si aggiunge subito l’inizializzazione a NULL nel costruttore ed il delete nel distruttore della classe e, di solito, si dorme tranquilli. Insomma, chi lavora con metodo non ha bisogno di questa caratteristica propria del JAVA… spacciata come grande novità, quando già il BASIC ce l’ha da sempre. In effetti, chi snobba C++ pensando che JAVA sia più moderno è forse chi non si rende conto di quanto JAVA e (Visual) BASIC siano simili 😉

    • Sicuramente non è così complicato gestire la memoria altrimenti non ci sarebbero così tante applicazioni per iOS! Sono d’accordo con te che facendo le cose con metodo non si hanno problemi ma personalmente mi “urta” dover scrivere codice per niente (o quasi). Alla fine il codice scritto resta lì e alla lunga la manutenzione del codice risulta più complicata via via che la dimensione delle classi aumenta. Questa la mia idea (di parte!)

      • Stefano Gemma

        Una classe scritta bene fa quel che deve fare e spesso viene corretta ma raramente aumenta di dimensione… comunque non è questione di dimensioni ma di qualità. Hai dimenticato un “dettaglio”, quando scrivi che passare a ObjectiveC non sarà tanto facile, pe ri programmatori C++: puoi programmare in C++ anche sotto iOS, in modo molto naturale e senza avere bisogno di strumenti aggiuntivi. Si può scrivere un intero programma in C++ per iOS, limitando l’ObjectiveC alla sola interfaccia con iOS stesso. ObjectiveC è di fatto uno “strato” aggiunto al C (e al C++) e viene mantenuta la sintassi del C/C++ stessi. Puoi richiamare anche metodi di classi ObjectiveC con la sintassi del C/C++. Il problema quindi non sta nella scelta del linguaggio. Sarebbe poco intelligente scegliere l’ambiente per cui sviluppare solo per via del linguaggio; come dire: non si dovrebbe scegliere android solo perché si conosce JAVA e non ObjectiveC/C/C++. Io, ad esempio, ho scritto alcune app sia per android (in JAVA) che per iOS (in ObjectiveC/C++) ma il primo giochino che ho pubblicato è stato per l’ambiente in cui si usa il linguaggio che conosco di meno: android/JAVA. La scelta si è basata su altre considerazione, di opportunità commerciale ma, soprattutto, di crescita professionale: ho scelto prima android proprio perché NON conoscevo JAVA e questo mi ha costretto ad impararlo.

        • Ok, puoi sviluppare anche in c++ ma qualcuno lo fa veramente? Io tutti gli esempi che ho visto in rete sono in ObjectiveC…
          Per quanto riguarda la scelta del linguaggio è ovviamente un discorso molto complicato. Dipende molto dalla complessità della cosa che devi sviluppare e dal budget del progetto (è brutto da dire ma la formazione costa). Se poi hai l’idea geniale che cambierò il mondo e un finanziamento infinito puoi scegliere che ti pare…

          • Stefano Gemma

            ehehehe… magari avessi o l’idea geniale od un finanziamento infinito! Non credo di essere l’unico al mondo a programmare in C++ per iOS/Mac OS X). Di solito lo fai per recuperare librerie che conosci bene, in C/C++, che ti costerebbe troppo rifare. Nel mio caso, uso le stesse lib per gestione database custom, parser di formule, odbc, socket, OpenGL ecc. in vari ambienti ed il C++ è l’unico linguaggio che mi permette di farlo (di quelli che conosco). Sono librerie ormai collaudate da una quindicina d’anni… non avrebbe senso riscriverle in ObjectiveC “puro”. Lo stesso vale per l’enorme numero di librerie in C disponibili, per risolvere i più svariati problemi. Non sempre il porting è possibile…ma, quando lo è, ti risparmiano più un sacco di lavoro. La logica dell’applicazione puoi sia scriverla in ObjectiveC che realizzare con questo linguaggio la sola interfaccia e demandare ad un oggetto di una classe C++ la gestione della app vera e propria. Ad esempio, quello che sto facendo ora è usare le mie librerie OpenGL in C++ per gestire tutta la grafica di un gioco, lasciando ad un semplice componente ObjectiveC l’onere di colloquiare con iOS, per creare la vista OpenGL. Gli eventi dell’applicazione verranno non gestiti direttamente da codice ObjectiveC ma direttamente da una classe C++ che rappresenta l’applicazione stessa. Perché tutti questi “strati”? Perché così puoi prendere le lib grafiche, la classe che gestisce la app ed usarle in un altro ambiente (ad esempio: VCL su Windows oppure wxWidgets su Win/Mac/Linux) oppure (perché no?) perfino con l’NDK su android! (cosa che vorrei evitare…).

  • Compagnoni Mirko

    Grazie per l’interessante articolo. Io sono un programmatore Java e vorrei imparare l’Object C. Il tuo articolo è un ottimo punto di partenza per chi si appresta a studiare uno dei due linguaggi. Ho capito quali saranno le difficoltà che dovrò affrontare.

  • Diego Novati

    Se la mia esperienza può contare devo dire che Object-C fa pagare un prezzo di ingresso molto elevato: linguaggio diverso dagli standard odierni, XCode completamente diverso dagli strumenti in uso oggi, convenzioni diverse, assenza dei package (Object-C è nato prima del C++, ed i package non esistevano ancora), però dopo la fatica della prima applicazione devo ammettere che lo sviluppo delle applicazioni successive procede in modo estremamente rapido dato che Apple fornisce librerie estremamente potenti e facili da usare (esempio: http sincrono, http asincrono e http delegato al sistema operativo secondo le esigenze del device per risparmiare batteria, ecc).

    Alla fine lo sviluppo per iOS è molto più rapido e semplice dell’equivalente su Android che, data la sua frammentazione, sta diventando ormai un incubo.

    Brevissimo retroterra culturale (ammetto la mia non giovanissima età): Assembler, C, C++, Pascal, Basic, Delphi, Visual Basic, C#, Java (J2EE, Spring, Android, JSF, ecc), Object-C, programmazione per tutti i dispositivi mobili usciti dal 1996.