Come creare una applicazione per Apple Watch con il linguaggio Swift

I numeri dicono sempre la verità. Apple ha venduto più di 12 milioni di Apple Watch in tutto il 2015 conquistandosi la nomina a leader del mercato globale dei wearable device.

E se sono poche le cose dovrebbero interessare uno sviluppatore, se escludiamo donne o uomini, quello che rimane in cima alla nostra lista è solamente una cosa: guadagnare con un’applicazione.

Non fraintendermi, se stai tramutando lo sviluppo di un’applicazione, in un mero interesse economico stai andando completamente fuori strada. Creare un’applicazione è un’arte che difficilmente può essere appagata dal guadagno. Ma, ovviamente, di sole idee e arte, non si vive.

Ciò non toglie il fatto che, con l’ormai affermarsi di nuove tecnologie in casa Apple, come watchOS e tvOS, ti si parano di fronte due nuove strade da percorrere:

  1. Lasciarti sfuggire quest’opportunità.
  2. Oppure iniziare a sviluppare applicazioni per Apple Watch.

Per lo sviluppo posso darti una mano io, mentre per la prima, rifletteteci bene perché nel giro di qualche anno, lo store sarà già troppo maturo e la competizione, per essere annoverati tra i big, maggiore.

Quindi, non perdiamoci in chiacchere, con questa guida voglio insegnarti come creare una applicazione per Apple Watch con il linguaggio Swift. Ti trasmetterò tutti i concetti di base e fondamentali che ti permetteranno di sviluppare app per watchOS in piena autonomia.

Imparerai a creare app per Apple Watch sviluppando una semplice applicazione per la gestione di una lista della spesa. Progetto già affrontato in altri tutorial e che ti permetterà di studiare i primi componenti di un progetto watchOS.

Dato che difficilmente un nuovo sviluppatore comincia con la creazione di un’app per watchOS, il tutorial è pensato per chi già sa creare applicazioni per iOS e per chi già conosce il linguaggio Swift. Se non sei tra questi, comincia adesso seguendo i miei corsi!

Pronto per imparare a creare app per Apple Watch? Allora cominciamo!

Applicazioni Native e WatchKit

Una delle prime caratteristica da tenere presente è che è possibile creare 2 generazioni di applicazioni per Apple Watch:

  1. Le applicazioni native per Apple Watch. Queste sono l’equivalente delle app che sviluppi per iPhone e iPad. In un progetto di questo tipo, l’applicazione risiede fisicamente nel tuo dispositivo da polso.
  2. La WatchKit app. Le app sviluppate con WatchKit nascono come estensione di un’applicazione per iPhone. In questo caso avrai un progetto di un’app classica per iOS diviso in due. Una parte è l’app classica per iOS ed un’altra quella per watchOS. Il WatchKit è un framework, come potrebbe essere l’UIKit o il CoreData per iOS, ti mette a disposizione delle classi per la progettazione dell’app per watchOS.

In realtà entrambe le versioni nascono come progetto iOS in simbiosi con un progetto WatchKit. La natività di un’applicazione watchOS è data dall’utilizzo del sistema operativo watchOS 2.0, infatti, grazie a questo le tue applicazioni risiederanno interamente sul dispositivo da polso anche se create utilizzando il sistema WatchKit.

Fatta questa piccola premessa, è logico pensare come l’applicazione che svilupperai, dato che sarà un gestore di una lista della spesa di una probabile app creata per iPhone, sarà sviluppata di pari passo all’app iOS quindi nella modalità WatchKit app.

Per capire il funzionamento di un’app WatchKit, immagina d’aver già sviluppato l’applicazione per iPhone per la gestione della tua lista e quindi di aver già creato la struttura dati per la conservazione di tutte le informazioni. Avrebbe senso ricreare una nuova struttura, da infilare nel watch, con gli stessi dati presenti su iPhone? La risposta è ovviamente no.

Un’app WatchKit puoi immaginarla, nella realtà è effettivamente così, come composta da 2 parti:

  1. Il primo pezzo, risiede sull’iPhone (o sul watch se la versione del sistema è la 2.0) ed è dove inserirai la logica dell’app WatchKit. Per logica intendo, il codice relativo all’aggiornamento della user interface del watch e la gestione degli eventi generati dalle interazione tra utente e orologio. Nel caso dell’app che creerai, la logica sarà composta dalla lista e dal codice per la gestione delle InterfaceController.
  2. L’altra parte è l’interfaccia utente. Lo storyboard, ad esempio, lo troverai all’interno di quest’area.

Le informazioni e la gestione degli eventi, dato che i due dispositivi non sono fisicamente collegati tra loro, passano attraverso wifi/bluetooth. Soprattutto quest’ultimo punto non deve assolutamente passare inosservato perché un sovraccarico d’informazioni causerà il rallentamento del watch e quindi una visualizzazione differita tra ciò che vorresti fosse visualizzato e ciò che realmente verrà osservato dall’utente.

In pratica, quando l’utilizzatore clicca su un bottone dell’applicazione, per esempio per l’aggiornamento della tabella, quello che succede è che l’evento generato dalla WatchKit app viene spedito, tramite wifi/bluetooth, all’iPhone. Una volta che il segnale arriva alla WatchKit Extension, quest’ultimo ne elabora il contenuto e lo rimanda indietro alla watch app, aggiornando così l’interfaccia con i nuovi dati acquisiti.

Setup del progetto

Apri Xcode e create un nuovo progetto da File\New\Project…, seleziona il template iOS App with WatchKit dalla lista watchOS\Application e premi su Next.

Setting progetto WatchKit app

Dai un nome all’applicazione, ad esempio: ListaSpesa, assicurati di aver selezionato il linguaggio Swift, deseleziona tutti i checkbox che trovi in fondo e clicca su Next. Scegli il Path in cui salvare il progetto e premi su Create.

Dai un’occhiata al Project Navigator sulla tua destra.

Anatomia di un progetto WatchKit con linguaggio swift

L’architettura di un’applicazione WatchKit è più evidente considerando cosa c’è effettivamente dentro ogni gruppo (sarebbe meglio dire Target). Lista Spesa WatchKit App, ad esempio, non contiene nessun tipo di source file ma solamente lo storyboard e gli assets per la creazione dell’interfaccia utente. Dall’altra parte, Lista Spesa WatchKit Extension contiene due file, InterfaceController.swift e ExtensionDelegate.swift, ma non lo storyboard.

Ora tutto ha più senso? alla WatchKit Extension è affidato il compito di gestire il comportamento della WatchKit App mentre quest’ultima deve amministrarne solamente l’interfaccia.

Build & Run

Accanto al bottone di Run del programma, nel riquadro dove visualizzi gli schemi, seleziona lo schema NomeProgetto WatchKit App.

Run di una watchOS app

Premendo il bottone Run (il triangolo in alto a sinistra), o Command-R, Xcode inizia il building della iOS App, dell’Extension, della WatchKit app. Successivamente installa tutte e 3 le parti all’interno dell’iOS Simulator e infine lo apre.

Se per caso il tuo iOS Simulator non dovesse mostrare l’Apple Watch, non ti allarmare, devi semplicemente attivarne la visualizzazione. Vai sul simulator e nella barra degli strumenti in alto, selezionate Hardware\External Displays\Apple Watch- 38 mm. Adesso dovresti vedere uno schermo nero raffigurante l’Apple Watch.

Costruire l’interfaccia di un watchOS app

Dallo sviluppo di applicazione iOS sai che le interfacce si costruiscono utilizzando lo storyboard, l’Auto Layout, Le Size Class e, da iOS 9, anche le Stack View.

Questo è parzialmente vero anche per la realizzazione di app per watchOS dove, nello specifico, le interfacce vengono realizzate utilizzando solamente lo storyboard ma non le tecniche di auto layout. Quest’ultime infatti risultano assenti per via delle dimensioni ridotte dello schermo, 38 mm e 42 mm, che essendo così piccole non godrebbero delle stesse proprietà dei dispositivi iOS.

Torna su Xcode. Dal project navigator apri il file Interface.storyboard che si trova nella cartella NomeProgetto WatchKit App.

Divisione Interface View watchOS app

Nell’interfaccia di un’applicazione per watchOS, differentemente da quanto avviene per un’applicazione iOS, non puoi dislocare gli elementi grafici a tuo piacimento.

La View di un’Interface Controller, è diviso in 3 aree verticali: TOP, CENTER e BOTTOM. Ogni nuovo elemento verrà sempre inserito a partire dalla top area tranne quando già saranno presenti elementi grafici, infatti in quest’ultimo caso, il nuovo oggetto, verrà impilato sotto quelli già esistenti.

Oltre al posizionamento verticale esiste l’equivalente orizzontale. In orizzontale, un oggetto, può essere schierato in altrettante 3 aree: LEFT, CENTER e RIGHT.

In concreto, puoi considerare la View come ad una scacchiera di dimensioni 3×3, ogni casella rappresenta un’area identificata dalle combinazioni possibili tra la componente verticale con quella orizzontale (left-top, center-top, right-top ecc).

Aggiungere un elemento

Lavoriamo per esempi pratici.

Dall’Object Library, cerca l’oggetto Label e trascinalo all’interno dell’Interface Controller. Adesso selezionalo, spostati nell’Attributes Inspector (il 3 bottone a partire da sinistra nel menu sopra l’Object Library) e, scorrendo un po’ il menu verso il basso, dovresti vedere la sezione Position composta da 2 attributi: Horizontal e Vertical. Modificando questi valori puoi riposizionare l’oggetto a tuo piacimento in una delle 9 caselle della scacchiera.

Ad esempio, mettendo horizontal: center e vertical: center, la label, verrà spostata immediatamente al centro del dispositivo:

Aggiungere un elemento all'interfaccia di un'app watchOS
Cosa succede quando aggiungete una nuova label?

Come previsto la nuova label viene inserita nell’angolo superiore sinistro perché di default, la componente orizzontale e verticale, è definita con quei parametri di default.

Adesso prova a posizionare la nuov label in posizione centrale, sia in orizzontale che verticale. Hai notato cos’è successo? entrambe le label sono entrate in conflitto per occupare la posizione centrale del dispositivo e, a discapito di quanto si potrebbe pensare, non vengono posizionate una accanto all’altra bensì, l’ultima label inserita, viene accatastata sotto la prima label.

Neanche provando a cambiare il parametro orizzontale di entrambe le label, mettendo la prima spostata verso left e la seconda verso right, i due oggetti si troveranno a condividere lo stesso spazio orizzontale. Come risolvere questo problema lo vedrete tra un po’.

Size di un elemento

Elimina le label che hai inserito e aggiungi un Button.

Button per watchOS app

Ti siete accorti che, anche se l’oggetto ha posizione left-top, occupa tutto lo spazio superiore dell’interfaccia?

Oltre ai vincoli di posizione, un altro fattore che influisce sull’interfaccia di un’applicazione è la dimensione o Size dell’oggetto.

Sotto al campo Position, nell’Attributes Inspector, c’è il campo Size che permette la modifica dell’estensione dell’oggetto in questione. I valori di larghezza (Width) e altezza (Height) vengono influenzati da 3 possibili proprietà:

  1. Relative to Container: imposta le dimensioni uguali a quelle del Container (per container si intende l’intera finestra dell’interfaccia).
  2. Size To Fit Content: ridimensiona l’oggetto in modo da racchiudere solamente ciò che contiene. Ad esempio il bottone, come qualsiasi altro elemento, sarà uguale alle dimensioni del testo contenuto al suo interno.
  3. Fixed: setta le dimensioni dell’oggetto in maniera statica, ovvero in base ad un valore numerico. Può essere modificato anche selezionando e trascinando uno degli angoli o bordi dell’oggetto selezionato.

Le prime due opzioni, relative e size to fit, sono proprietà dinamiche, infatti sono in grado di adattarsi in base al cambiamento delle dimensioni sia del dispositivo. Ti ricordo che esistono due versione di Apple Watch con dimensioni dello schermo differenti. Il mio consiglio è quello di utilizzare sempre una di queste due opzioni onde evitar di dover riadattare la grafica dell’applicazione a runtime.

Il parametro larghezza, nel bottone che hai inserito, è settato uguale a quella del container, mentre la dimensione in verticale è relativa all’altezza del testo contenuto. Se provi a modificare la larghezza in: Size To Fit Content il bottone si ridimensionerà occupando solo lo spazio occupato dalla parola “button”. Adesso con un doppio click sul bottone rinominalo utilizzando una parola più lunga e, con le impostazioni che gli hai assegnato, dovrebbe allargarsi in base alla larghezza del testo contenuto.

Proprietà Size di un elemento grafico di app watchOS WatchKit swift

Mettere insieme più elementi con i Group

L’ultima nozione basilare che ti serve per comporre un’interfaccia è quella della dislocazione di più oggetti sullo stesso livello. Da quanto fin ora spiegato sai che un oggetto, qualsiasi sia il suo tipo di collocazione, non può essere posizionato accanto ad un altro. Il motivo risiede nella quantità di informazioni che effettivamente possono stare su una riga.

L’Apple Watch ha uno schermo di dimensioni veramente ridicole se paragonate a quelle di un’iPhone e, per questo motivo, Apple da per scontato che non verranno inserite grandi quantità di informazioni visive che indurrebbero l’utente a dover avvicinare il viso all’orologio.

Però c’è un modo per poter ovviare al presunto problema e la risposta è nell’oggetto Group. Elimina tutto ciò che hai all’interno dell’Interface Controller e trascina, sempre dall’Object Library, un oggetto Group all’interno dell’interfaccia.

L’oggetto Group crea un container posizionabile in una delle 9 caselle dell’Interface Controller. Un Group crea una nuova sotto griglia 3×3 dove posizionare gli oggetti grafici.

Group e dislocazione di più elementi nello stesso quadrante watchOS

Dato che di default un group è trasparente, per capire cosa voglio dire, selezionate il group e dall’Attributes Inspector cambia il colore di background (l’attributo Color per l’esattezza) in uno a tua scelta. Adesso se provi ad inserire due label, una accanto all’altra, all’interno del group noterai come esse vengano visualizzate effettivamente una accanto all’altra.

Cambiando la position di una delle due label in horizontal: right e vertical: top, dovresti vederle sempre sulla stessa linea ma diametralmente opposte rispetto all’asse centrale.

Sei riuscito a mettere una label sotto una presente nel group? don’t worry! oltre alla dislocazione orizzontale, esiste quella verticale e per attivarla vi basta cambiare, sempre dall’Attributes Inspector e dopo aver selezionato il group, la voce Layout da Horizontal a Vertical.

Interfaccia del progetto

Una regola generale per la costruzione di una qualsiasi applicazione è quella di partire dalla realizzazione dell’interfaccia utente.

L’interfaccia dell’applicazione che state realizzando è composta da 3 Interface Controller, la prima sarà una schermata di benvenuto con il numero di oggett da compare, la seconda mostrerà la lista della spesa e l’ultima verrà utilizzata per visualizzare i dettagli dell’appuntamento selezionato dalla seconda interfaccia.

Il primo passaggio da fare è quello di eliminare qualsiasi cosa tu abbia inserito nel primo Interface Controller. Successivamente aggiungi una Label e posizionatela in top-center, fai doppio click su di essa e cambia il testo in “Ciao”. Aggiungi un Group e ubicalo in center-center. All’interno del gruppo inserisci 2 Label. Colloca la prima label in left-center e, facendo doppio click su di essa, cambiate il testo in “0”. Questa label la utilizzerai per mostrare il numero di appuntamenti in programma.

La seconda label posizionatela, sempre all’interno del group, in right-center e cambiale il testo in “da comprare”. Inserisci un Button e posizionalo in center-bottom, rinominalo in “Vedi Lista” e se preferisci cambia il Color di background.

Interfaccia app WatchKit 1 Dall’Object Library prendi un oggetto Interface Controller e riponilo accanto a quello appena creato. Al suo interno trascina un oggetto Table.

Selezionate la Cell, cambia il Color di sfondo in uno a tua scelta e, se vuoi maggiormente stilizzarla, modificate la voce Radius per arrotondare i bordi del rettangolo che la descrive. All’interno della cella trascinate una Label e sistematela in center-center. In questa label verrà mostrato il nome della persona da incontrare.

Interfaccia app WatchKit 2

Non c’è bisogno di aggiungere nient’altro perché la tabella funziona alla stessa maniera, o quasi, di quelle utilizzate per iOS. Il funzionamento verrà ripreso durante l’implementazione del codice.

Se stai cercando un tutorial in cui ampliare le tue conoscenze sulle tabelle del WatchKit, questo è il tutorial che fa per te.

Allo stesso modo aggiungi, accanto all’ultimo inserito, un nuovo Interface Controller. Inserite una Label in top-center e rinominatela in “nome”. Sotto la seguente label, posizionane una nuova in center-top, cambia l’attributo Lines in 3 (in modo da far entrare tutto il testo) e modifica la Size larghezza in Relative to Container.

Infine dovresti avere il seguente layout:

Schermata 2016-05-02 alle 12.31.11

I 3 avvisi mostrati da Xcode verranno corretti successivamente.

InterfaceController e Life Cycle

Un oggetto di tipo InterfaceController è un’istanza della classe WKInterfaceController o più precisamente di una sua subclass. La WKInterfaceController è contenuta all’interno del framework WatchKit.

Da watchOS 2.0 in sù questa classe gira localmente sul dispositivo da polso. Mentre, nella versione watchOS 1.0 la classe risiede sull’iPhone e, di conseguenza, l’app doveva essere obbligatoriamente utilizzata in connessione con l’app iOS.

Nel Project Navigator di Xcode, vai alla cartella NomeProgetto WatchKit Extension e apri il file InterfaceController.swift. La classe che troverai all’interno è il controller, creato di default da Xcode, per la gestione della prima interfaccia presente nello storyboard.

 

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        // Configure interface objects here.
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }

}
  • awakeWithContext(context:), chiamato dopo il costruttore init, inizializza l’InterfaceController con i dati passati dal context. Il context può essere opzionale in quanto rappresenta le informazione passata da un controller precedente. Dato che è il primo metodo ad essere invocato, l’awakeWithContext(context:) viene utilizzato per tutte quelle operazioni preparatorie alla visualizzazione dell’interfaccia all’utente. Ad esempio, l’inizializzazione delle informazioni contenute nelle label, tabelle, immagini ecc viene eseguita all’interno del seguente metodo. Nel caso dell’ultima InterfaceController, modificherete l’awakeWithContext(context:) per cambiare il testo contenuto dalle label con le informazioni passate dal context.
  • willActivate() viene chiamato non appena l’awake ha finito il suo ciclo d’esecuzione e quindi qualche istante prima che l’interfaccia verrà presentata all’utente. Dato che l’esecuzione avviene nel lasso di tempo in cui l’interfaccia viene renderizzata, è sconsigliato eseguire, all’interno di questo metodo, operazioni di inizializzazione dispendiose le quali potrebbero bloccare il watch. Questo non vuol dire: “non dovete mettere metodi di aggiornamento dell’interfaccia”, bensì vanno inserite esclusivamente le operazioni di brevissima durata, come ad esempio il cambio del testo in una label o l’aggiornamento di una tabella con pochi dati.
  • didDeactivate(), viene chiamato quando l’interface controller di riferimento non è più visualizzato o quando l’iPhone passa allo stato di Lock. Un controller in questo stato può essere deallocato in qualsiasi momento e per questo motivo, all’interno del metodo didDeactivate(), potete inserire delle operazioni di cleanup del progetto come lo stop di timer o il salvataggio di alcune informazioni. Non utilizzate questo metodo per la modifica dell’interfaccia, infatti quando esso viene chiamato l’interfaccia non è più visualizzata dal watch e quindi ogni modifica inserita ne risulterebbe superflua.

Quando l’applicazione WatchKit viene lanciata in esecuzione, il primo metodo che viene chiamato dal sistema, dopo il caricamento della struttura dell’interfaccia dallo storyboard, è il metodo init e successivamente l’awakeWithContext(context:). Quest’ultimo provvede ad inizializzare la user interface dandogli i valori e le informazioni principali (in questo momento l’interfaccia è in caricamento e non è ancora visualizzata sul watch).

Una volta eseguiti i metodi di inizializzazione viene immediatamente visualizzata l’interfaccia dell’applicazione con precedente chiamata al metodo willActivate().

A questo punto l’applicazione è pronta per essere utilizzata: ad esempio, un click su un bottone invierà un segnala alla rispettiva action la quale rimanderà indietro all’Apple Watch il segnale elaborato o l’operazione da eseguire; mentre nell’ipotesi in cui venisse eseguito un push verso un altro controller, il nuovo controller verrebbe istanziato eseguendo un nuovo ciclo di vita indipendente dal controller precedente (ripartendo dall’awakeWithContext(context:)).

Qualora l’utente ritornasse indietro, dato che il controller di partenza era stato già istanziato, verrebbe eseguita solo la willActivate() sempre qualche istante prima della visualizzazione dell’interfaccia. Quando l’utente interromperà l’applicazione o l’iPhone passerà in lock, verrà lanciata la didDeactivate() che provvederà, se il programmatore l’ha previsto, ad interrompere alcuni task o a salvare i dati modificati.

condividi xcoding

Ho impiegato un po’ di tempo a scrivere questo tutorial. Sarei davvero felice se contribuissi al mio progetto semplicemente mettendo un mi piace o follow alle mie pagine.

[addtoany]

[mailmunch-form id=”101287″]

Grazie davvero :-)

Controller, Outlet e Segue

Dopo aver creato l’interfaccia, il secondo passaggio da fare è quello relativo al collegamento degli oggetti interattivi dell’applicazione, o soggetti a cambiamento, con il rispettivo codice di controllo.

Il primo passaggio da fare è creare 2 classi di riferimento per le interface controller dell’applicazione non ancora associate ad una custom class.

All’interno del group, NomeProgetto WatchKit Extesion, devi aggiungere 2 nuovi file, quindi clicca con il tasto destro sul nome del gruppo e seleziona New File. Dal menu WatchOS\Source scegli WatchKit Class e premi Next. Cambiate la subclass of in WKInterfaceController, rinomina la classe in TableInterfaceController e seleziona Swift come linguaggio. Nella finestra di selezione della cartella in cui salvare il file, assicurati che, nel riquadro in basso, sia selezionato il target: NomeProgetto WatchKit Extension.

Esegui le stesse operazioni per creare un nuovo file di tipo WKInterfaceController. A quest’ultimo dai il nome di DetailInterfaceController.

new source file watchkit Adesso torna allo storyboard e seleziona l’interface controller composto dalla tabella. Dal menu Utilities passa alla voce Identity Inspector e nel campo Class inserisci il nome della classe creata in precedenza: TableInterfaceController. Premi invio.

La stessa identica operazione eseguila per l’ultima interfaccia assicurandoti di inserire, nel campo Class, la DetailInterfaceController:

Associare una classe ad Interface Controller

Sempre dallo storyboard, seleziona il primo interface controller e apri l’Assistant Editor. Seleziona la label con il testo “0”, premi CTRL+Click Sinistro, o solamente Click Destro e trascina, tenendo premuto i tasti, la freccia verso l’interno della classe InterfaceController.

Nel box per la creazione della IBOutlet, inserisci come Name: label_numeroElementi. Alla label_numeroElementi verrà cambiato il testo in base al numero di oggetti ancora da comprare.

Dato che gli altri elementi dell’interfaccia sono statici, a parte il bottone che ora visualizzi, non c’è bisogno di creare una outlet per la loro gestione. Il bottone serve esclusivamente per passare dalla InterfaceController alla TableInterfaceController.

Il sistema di passaggio tra controller è simile a quello utilizzo su iOS e anche qui prende il nome di segue. Selezionate il bottone, tenendo premuti gli stessi comandi utilizzati per le outlet, trascina, all’interno dello storyboard, la freccia verso la TableInterfaceController. Scegli come Action Segue: Push. Se tutto è andato per il verso giusto, dovresti vedere una freccia che collega l’InterfaceController alla TableInterfaceController.

Outlet e Segue WatchKit

Cell Identifier tabella

La TableInterfaceController ha al suo interno una tabella che essendo composta da custom cell, perché hai inserito una label all’interno della cella, deve essere gestita da una classe apposita. All’interno del file TableInterfaceController.swift, sotto l’intero corpo della classe TableInterfaceController, create una nuova classe chiamata TableRowController come subclass della NSObject:

 

 

class TableInterfaceController: WKInterfaceController {

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
    }

    override func willActivate() {
        super.willActivate()
    }

    override func didDeactivate() {
        super.didDeactivate()
    }

}

class TableRowController : NSObject {
    
}

Torna allo storyboard e clicca sulla TableInterfaceController. Onde evitare errori, dal Document Outline, selezionate la Table e premendo sempre i bottoni per i collegamenti, trascinate la freccia verso l’interno della classe TableInterfaceController e rinomina l’outlet in table_listaSpesa.

Sempre dall’outline selezionate la Table Row Controller e dal menu Identity Inspector cambia la classe di riferimento in TableRowController.

Ancora per la Table Row Controller, passa al menu Attributes Inspector e cambiate l’Identifier in TableRowController. In questo modo il controller che gestisce le row della tabella è impostato per funzionare secondo le specifiche che inserirai nella classe TableRowController.

TableRowController e identifier cell

Seleziona la label che hai inserito all’interno della cella della tabella e trascinate la freccia verso l’interno della classe TableRowController. Rinomina l’outlet in label_nomeAlimento.

class TableRowController : NSObject {
    @IBOutlet var label_nomeAlimento: WKInterfaceLabel!
    
}

L’ultimo passaggio, per questo controller, è quello relativo al segue che collega il tocco su una row della tabella, al controller dei dettagli dell’appuntamento. Dallo storyboard seleziona la tabella e crea un segue di tipo push con la DetailInterfaceController.

Per il DetailInterfaceController, create le outlet delle due label presenti. La prima chiamatela label_nomeAlimento, servirà per mostrare il nome dell’alimento da acquistare, e la seconda label_dettagliAlimento, mostrerà dei dettagli dell’alimento.

label cella e altri identifier

L’implementazione del codice

Per prima cosa, all’interno del NomeProgetto WatchKit Extension, create un nuovo file di tipo Swift File chiamato Alimento. Al suo interno inserisci il seguente codice:

import Foundation

class Alimento {
    var nome: String!
    var dettagli: String!
    
    init(nome: String, dettagli: String) {
        self.nome = nome
        self.dettagli = dettagli
    }

}

 

La classe Alimento è composta, come si evince dall’interfaccia, da soli due attributi: nome e dettagli. L’attributo “nome” verrà utilizzato per identificare l’alimento da acquistare mentre l’attributo “dettagli” indicherà qualche sorta di promemoria. Il costruttore init inizializza l’oggetto con le stringhe passate come parametro.

Apri il file InterfaceController.swift e all’interno della classe, crea una lista, chiamata listaSpesa, contenente alcune istanze della classe Alimento:

 

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {
    
    @IBOutlet var label_numeroElementi: WKInterfaceLabel!
    
    var listaSpesa = [
        Alimento(nome: "Pasta", dettagli: "Preferibilmente rigata"),
        Alimento(nome: "Pollo", dettagli: "intero e non a fette"),
        Alimento(nome: "Piatti e bicchieri", dettagli: "Di plastica")
    ]
    
    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
    }

    override func willActivate() {
        super.willActivate()
    }

    override func didDeactivate() {
        super.didDeactivate()
    }

}

Ora che hai la struttura dati, puoi aggiornare il testo della label_numeroElementi. Dove aggiorniamo il valore della label? Nell’awakeWithContext(context:) o nel willActivate()?

Se il valore che state per aggiornare è di tipo statico e non è soggetto a cambiamenti nel tempo, la risposta è il metodo awakeWithContext(context:). Se invece l’informazione è soggetta a mutamenti, come nel caso del numero di alimenti, allora è lecito utilizzare la willActivate().

Per modificare il testo della label, all’interno del metodo willActivate(), aggiungi il seguente codice:

    override func willActivate() {
        super.willActivate()
        
        self.label_numeroElementi.setText("\(listaSpesa.count)")
    }

Il metodo che la classe WKInterfaceLabel ti mette a disposizione, per la manipolazione del testo della label, si chiama setText.

Avviando l’applicazione, la label_numeroElementi, dovrebbe mostrare il numero 3.

L’ultimo passaggio da fare, per completare la InterfaceController, è quello di modificare il segue in modo da passare la lista alla TableInterfaceController che ne provvederà a visualizzarne il contenuto nella tabella. Sotto uno dei metodi della classe InterfaceController, aggiungi il seguente codice:

    override func contextForSegueWithIdentifier(segueIdentifier: String) -> AnyObject? {
        return self.listaSpesa
    }

Il segue, come per la programmazione iOS, ha un Identifier che lo marca nel caso in cui fossero presenti più segue che partano dalla stessa interfaccia. Nel nostro caso il segue che esce dall’InterfaceController è solo uno e per tanto non ha motivo di essere targato tramite Identifier.

Se ti ricordi, nell’awakeWithContext(context:), il context è l’oggetto che viene passato durante gli spostamenti tra le interfacce e che quindi identifica l’informazione che un controller passa all’altro.

La contextForSegueWithIdentifier(segueIdentifier:) crea l’oggetto context dal quale, il controller destinatario, leggerà i dati. In questo modo, quando verrà premuto il bottone per spostarsi alla TableInterfaceController, il context, letto dal metodo awakeWithContext(context:), sarà un array di oggetti Alimento. Il fatto che la funzione contextForSegueWithIdentifier(segueIdentifier:) ritorna un AnyObject opzionale ti da la possibilità di spedire qualsiasi tipo d’informazione.

La tabella

Spostati nel TableInterfaceController.swift e sotto l’IBOutlet crea una lista di oggetti Alimento dove poter inserire le informazioni che il context passerà:

class TableInterfaceController: WKInterfaceController {
    
    @IBOutlet var table_listaSpesa: WKInterfaceTable!
    
    var listaSpesa :[Alimento]!

Nel metodo awakeWithContext(context:) eseguite un casting del context al tipo Appuntamento e infine passatelo alla variabile appuntamenti:

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        guard let oggetto_ricevuto = context else {
            return
        }
        
        self.listaSpesa = oggetto_ricevuto as! [Alimento]
        
    }

Una volta che la lista appuntamenti è stata riempita, con i valori passati dal context, devi provvedere a mostrarla nella tabella. Per inserire i dati all’interno della tabella è necessario:

  1. creare una funzione che setti il numero di righe della tabella uguale a quello del numero di elementi della lista.
  2. istanziare le varie custom cell con il contenuto dell’array.

All’interno della classe TableInterfaceController, aggiungi il codice:

    private func loadTable() {
        self.table_listaSpesa.setNumberOfRows(self.listaSpesa!.count, withRowType: "TableRowController")
        
        for (index, appuntamento) in self.listaSpesa!.enumerate() {
            if let row = self.table_listaSpesa.rowControllerAtIndex(index) as? TableRowController {
                row.label_nomeAlimento.setText(appuntamento.nome!)
            }
        }
    }

 

La setNumberOfRow(withRowType:) imposta sia il numero di righe, che il tipo di controller che utilizzerà la riga per mostrare il suo contenuto. Il withRowType fa riferimento all’Identifier impostato alla TableRowController. Una volta stabilito il numero di righe, il ciclo, dopo aver recuperato la row all’indice index (uguale al numero identificativo generato dall’enumerazione dell’array – self.listaSpesa!.enumerate()), cambia il testo della labe_cell mettendolo uguale al nome dell’appuntamento iterato. La funzione adesso è pronta per essere chiamata all’interno della willActivate():

    override func willActivate() {
        super.willActivate()
        self.loadTable()
    }

Prova per credere! Avvia l’applicazione e spostati, premendo il bottone, alla TableInterfaceController.

run app watchOS

Per concludere con la TableInterfaceController devi preparare il context per l’invio dell’informazione alla DetailInterfaceController. Il metodo in questione è leggermente diverso rispetto a quello visto in precedenza, infatti è creato appositamente per generare un context al tocco di un elemento in una riga della tabella. Il codice è il seguente:

    override func contextForSegueWithIdentifier(segueIdentifier: String, inTable table: WKInterfaceTable, rowIndex: Int) -> AnyObject? {
        return self.listaSpesa![rowIndex]
    }

Anche in questo caso non eseguiamo nessun controllo sull’Identifier del segue e semplicemente prendendo la rowIndex, passata come parametro al tocco della riga, recuperiamo l’appuntamento relativo a quell’indice e lo ritorniamo al context.

Nella DetailInterfaceController, all’interno dell’awakeWithContext(context:), esegui il casting in Alimento e, dato che le informazioni sono statiche, cambia direttamente il testo delle due label:

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        guard let elem_ricevuto = context else {return}
        let alimento = elem_ricevuto as! Alimento
        
        self.label_nomeAlimento.setText(alimento.nome)
        self.label_dettagliAlimento.setText(alimento.dettagli)
    }

Conclusione

A questo punto l’applicazione di base è conclusa! adesso nella vostra cassetta degli attrezzi avete i primi strumenti per la realizzazione delle applicazioni per Apple Watch utilizzando il framework WatchKit.

Da questo tutorial, puoi passare ai seguenti:

Buona Programmazione!

Salvare immagini in Memoria con Core Data

Questo è un estratto di un intero modulo del corso di sviluppo applicazioni iOS con Swift. Buona lettura ;)

Nella prima lezione introduttiva al Core Data, nelle impostazioni delle Entity, ti ho fatto notare la non presenza di un tipo di dato che descrivesse un’immagine. Questo non deve trarti in inganno perché ciò non significa che il Core Data non permetta il salvataggio delle immagini in memoria.

Generalmente il salvataggio d’immagini in un Database è un’operazione, spesso e volentieri, sconsigliata per via delle dimensioni notevoli che possono assumere alcune immagini. In genere non si salvano mai immagini superiori ad 1 MB perché i database comincerebbero a perdere la famosa velocità osannata nel tutorial introduttivo.

Come si fa? L’approccio più utilizzato è quello di memorizzare all’interno del database il path o percorso del documento/immagine. Grazie a questo path si riesce a raggiungere il vero e proprio file che, in molti casi, viene conservato in una cartella specifica.

Ora, se ricordi bene, ti ho detto che il Core Data non è un Database bensì una tecnologia che fa da intermediario. Quindi la vera domanda è: com’è che riusciremo a salvare le immagini in memoria con il Core Data?

Tra i tipi di dati possibili, per gli attributi di una Entity del Core Data, è presente anche il Binary Data (dati in formato binario). Per non dilungarmi troppo sulla natura dei file binari, ti dico subito che qualsiasi oggetto può essere rappresentato in notazione binaria: cioè come file composto da 0 e 1, ovvero in bit (bit = l’unità fondamentale di qualsiasi computer).

Binary Data Core Data

Utilizzando il tipo di dato Binary Data sarai in grado di salvare le immagini con il Core Data. Ovviamente, non è possibile inserire l’UIImage nella proprietà che ha il tipo binary data. Infatti, com’è plausibile, è necessaria un’opportuna conversione da UIImage in NSData (l’oggetto che descrive i Binary Data).

Piccola digressione. L’NSData non è la classe per la rappresentazione delle date del calendario. C’eri cascato pure tu? In inglese “data” significata “dati o informazione”. Mentre la classe che descrive le date del calendario è la NSDate. Piccole pillole che possono salvare il tuo progetto dall’autocombustione.

External Storage

In effetti salvare un’immagine su Binary Data non è comunque una scelta ottimale. Le immagini, come ti dicevo, hanno un peso che supera i megabyte che le renderebbero pesanti anche se fossero convertite in formato binary data.

Il Core Data oltre a fornirti il salvataggio in Binary Data, ti permetterà di salvare l’informazione convertita in NSData in una posizione differente rispetto al database nel quale verrà conservato l’NSManagedObject. L’NSManagedObject risiederà normalmente nel Database, mentre, l’immagine convertita in binary data verrà posizionata nel File System del tuo iPhone/iPad (per semplicità puoi pensare le immagini come salvate in una cartella del tuo dispositivo). Così facendo il recupero degli oggetto NSManagedObject risulterà più veloce ed immediato.

Per abilitare il salvataggio di una proprietà Binary Data direttamente sul File System devi selezionare l’opzione “Allow External Storage”:

allow external storage core data

L’Allow External Storage non avrà nessuna ripercussione sulla tua proprietà Binary Data. Dunque, anche se abilitato, l’immagine, verrà sempre restituita in formato Binary Data ovvero come oggetto NSData. 

Codice

Dato che concettualmente le nozioni sono uguali alle lezioni precedenti, l’unico step da analizzare è la conversione di un’UIImage in NSdata e viceversa. Ti ricordo che, se stai lavorando con le UIImageView, l’immagine è contenuta all’interno della proprietà image.

Nel mio progetto ho una Entity con due proprietà. Una proprietà “nome” che descriverà l’immagine ed una proprietà “binary_img” che conterrà l’immagine.

Una volta che avrai creato la classe di riferimento, entra dentro l’extension ed aggiungi la seguente funzione (assicurati di aver importato l’UIKit):

import Foundation
import CoreData
import UIKit

extension Immagine {

    @NSManaged var nome: String?
    @NSManaged var binary_img: NSData?
    
    func image_toNSData(image: UIImage) -> NSData? {
        
        guard let data = UIImageJPEGRepresentation(image, 1) else {
            print("conversione immagine fallita")
            return nil
        }
        
        return data
    }

}

Il metodo UIImageJPEGRrepresentation trasforma una UIImage da qualsiasi formato utilizzato in JPEG in formato Binary Data (come NSData). Infatti il metodo restituisce un NSData nel caso di conversione avvenuta con successo o nil altrimenti. Il secondo parametro definisce la compression quality, cioè la qualità che dovrà mantenere l’immagine una volta convertita. Un valore uguale ad 1 mantiene la qualità dell’immagine originale. Più ci si avvicina allo zero e più calerà la qualità e, automaticamente, anche il peso.

Ti basterà utilizzare questo metodo per salvare l’immagine dentro la tua proprietà NSData.

Al contrario, per convertire l’NSData in UIImage, potrai utilizzare il costruttore della classe UIImage che accetta in ingresso un NSData:

    func data_toUIImage() -> UIImage? {
        
        guard let image = UIImage(data: self.binary_img!) else {
            print("conversione immagine fallita")
            return nil
        }
        
        return image
    }

Thumbnail e aumento delle prestazioni

Un sistema intelligente per l’ottimizzazione degli spazi e della velocità di caricamento degli oggetti è quella di utilizzare una versione ridotta o Thumbnail dell’immagine originale.

Pensa, per esempio, ad una tabella che mostra 100 o più elementi e dove, ad ogni riga, deve mostrare un’anteprima dell’immagine. Un conto sarà caricare 100 immagini con massima risoluzione ed un altro conto sarà fare la stessa operazione con immagini ridotte.

Poco fa ti ho fatto vedere che il metodo UIImageJPEGRrepresentation ti da la possibilità di creare un NSData di un’immagine con risoluzione inferiore all’originale (modificando il secondo parametro). Potremmo, quindi, sfruttare tale proprietà per creare delle versioni ridotte delle immagini originali.

Ma, dove aggiungere la versione ridotta dell’immagine?

Aggiungere una nuova proprietà NSData all’Entity che descrive l’immagine originale (o comunque dove è presente l’oggetto principale) non è la scelta ottimale. Avresti due proprietà NSData con lo stesso contenuto che appesantirebbero inutilmente l’oggetto.

La strategia da adottare è quello di una seconda Entity, chiamata Thumbnail, collegata con una relazione One-To-One all’Entity Principale. All’interno di questa salverai l’immagine ridotta con lo stesso sistema visto poco fa:

Thumbnail e Core Data

Ovviamente il ragionamento può essere fatto anche al contrario. Ovvero la thumbnail può essere inserita nell’Entity principale e l’immagine originale in un’altra. Cosa che renderebbe più leggera l’entity nel caso in cui lavorassi principalmente con questa.

Tutto dipende dall’utilizzo che fai delle Entity. Se utilizzi un’entity più spesso rispetto ad un’altra, inserisci la thumbnail in questa e l’immagine originale in un’Entity associata.

Considerazioni

Non ho voluto creare un esempio perché effettivamente non c’è molto da provare. Sarebbe un cut and paste dei codici delle precedenti lezioni. Quindi ho preferito descrivere in maniera più veloce questa proprietà per darti subito modo di mettere in pratica queste conoscenze.

Per qualsiasi dubbio sull’utilizzo di quest’opzione, lascia pure un commento.

Buona Programmazione!

NSUserDefaults in Swift. Salvare piccole quantità d’informazioni

Spesso ti capiterà di dover salvare piccole quantità di informazioni dell’utente e di non voler utilizzare sistemi complicati come potrebbero essere il CoreData, i file Plist ecc. Per questo motivo, un sistema semplice e al tempo stesso potente, risulta essere l’NSUserDefault.

L’NSUserDefaults è una classe che permette di interagire con un “Database” (in realtà è un file Plist binario) persistente creato appositamente per ogni applicazione. Persistente significa che, i dati che salverai, continueranno ad esistere anche dopo la chiusura dell’app o aggiornamento.

L’NSUserDefaults, ascoltami bene, nasce esclusivamente per la memorizzazione di piccole quantità di informazioni. Se vuoi una misura delle quantità massima, si consiglia, di non superare il centinaio di KB (kilobyte). Anche se un limite reale non è realmente fissato, solamente per tvOS viene fissato a 500kb, la community dei sviluppatori concorda sul non superare tali limiti.

Perché così poco?

Perché l’NSUserDefaults è una classe Singleton che, oltre a salvare le informazioni in un database basato su file binary plist, riesce a fornirti i dati quasi istantaneamente. In pratica, quando salvi un’informazione con l’NSUserDefaults in Swift viene archiviata e contemporaneamente conservata in memoria RAM per evitare di recuperarla dal DB ogni volta che ti serve (quello che comunemente viene chiamata Cache).

Il problema ricade in questa duplice natura dell’NSUserDefaults. Da un lato salva in in un database che possiede l’utente e, contemporaneamente, tiene questi dati in memoria RAM. In più, il fatto che è una classe Singleton, ogni richiamo dell’oggetto richiamerà tutti i dati salvati in memoria (anche quelli che, paradossalmente, utilizzerai una sola volta in tutta la tua applicazione).

Devi immaginare l’NSUserDefaults come un dizionario chiave-valore. Ogni informazione che vorrai salvare dovrà essere associata ad una chiave univoca e statica, cioè che non cambia nel tempo. Per farti un esempio, immagina di avere una pagina delle impostazioni. In questo ViewController delle impostazioni, l’utente può selezionare un colore custom per lo sfondo della tua applicazione.

Con l’NSUserDefaults potrai salvare questo valore, che sarà composto dalla componente RGB, all’interno di una chiave che potrai chiamare “userBackgroundColor” (il nome lo decidi tu). In questo modo, quando l’applicazione dovrà recuperare le impostazioni dell’utente e il colore custom, richiamerà questa chiave dall’NSUserDefaults.

Anche se il tutorial è abbastanza semplice. Se sei alle prime armi ti consiglio di seguire un percorso più lineare e di formare ottime basi del linguaggio Swift

Premessa fatta! Pronto a vedere l’NSUserDefaults in Swift?

Scrivere un’informazione

Crea un normalissimo progetto Single View Application per iOS e spostati nello storyboard. Aggiungi due textField ed un bottone. Nella prima, l’utente, inserirà il nome dell’utente e, nella seconda, l’età. Il bottone salverà i dati nell’NSUserDefaults.

Questo è un progetto a scopo didattico. Informazioni del genere non andrebbero salvate nell’NSUserDefaults in quanto potrebbero essere incastonate dentro una classe e, di conseguenza, necessiterebbero di sistemi leggermente più avanzati (ma tutto dipende dal tipo di applicazione che stai realizzando):

Schermata 2016-02-22 alle 00.35.10

Nella IBAction associata al bottone aggiungi il codice di controllo sul testo delle due textField:

    @IBAction func saveInfo_clicked(sender: UIButton) {
        guard !self.txt_nome.text!.isEmpty else {
            return
        }
        
        guard !self.txt_età.text!.isEmpty else {
            return
        }
        
        let nome = self.txt_nome.text!
        let età = self.txt_età.text!
        
    }

Per recuperare lo spazio utente in cui salvare i dati, cioè l’User Defaults, basta utilizzare la class func standardUserDefaults() della classe NSUserDefaults. Essendo una class func restituisce l’oggetto singleton della classe NSUserDefaults.

Quindi, subito dopo il recupero del nome e dell’età, aggiungi:

let defaults = NSUserDefaults.standardUserDefaults()

Adesso che hai il riferimento all’NSUserDefaults dell’utente, puoi salvargli dentro le informazioni. Ogni informazione che vorrai salvare, come già ribadito, deve essere associata ad una chiave di tipo String univoca. Questo vuol dire che una volta che memorizzerai una chiave non potrai modificarla.

I metodi per il salvataggio dei tipi di dato prevedono due parametri. Il primo è l’informazione da salvare ed il secondo, chiamato forKey, è la String a cui verrà associato questo dato:

  • setBool(_ :Bool, forKey: String): Salva un valore booleano associato ad una chiave identificativa (forKey).
  • setInteger(_ :Int, forKey: String): Salva un valore intero.
  • setDouble(_ :Double, forKey: String): Salva un valore Double.
  • setFloat(_ :Float, forKey: String): Salva un valore Float.

Dove sono le String? i vettori ecc?

Per poter salvare gli altri tipi di dato bisogna utilizzare il metodo setObject(_: AnyObject?, forKey: String) che, come primo parametro, accetta un AnyObject. Quindi, per esempio, è possibile fare la seguente:

        defaults.setObject(["ciao", "xcoders"], forKey: "array")
        defaults.setObject("stringa", forKey: "stringa")

Anche se il parametro accetta un AnyObject, l’NSUserDefaults ti permette di salvare solamente: Array, Dizionari e Stringhe. Un caso particolare sono gli NSDate (il tipo di dato delle date del calendario) e l’NSData (un tipo di dato per il salvataggio di qualsiasi dato). Pur dandoti la possibilità di salvare un NSData, ciò non vuol dire che potrai salvare qualsiasi cosa. Infatti, ribadisco che, per salvare grandi quantità d’informazioni come foto, oggetti intesi come istanze di classe, bisogna utilizzare altri sistemi di memorizzazione come il CoreData o il CloudKit.

La funzione setObject è relativamente nuova. É stata introdotta con iOS 8 e, sicuramente, con le prossime release il campo di dati permessi verrà ampliato.

Fatto questo piccolo excursus sui metodi, torniamo al nostro progetto.

Proviamo a memorizzare i dati dell’utente. Quindi, aggiungi nell’NSUserDefaults la stringa nome associata ad una chiave chiamata “UserName” e la stringa età, che trasformerai in Int, nella chiave “UserAge”:

        let defaults = NSUserDefaults.standardUserDefaults()
        
        defaults.setObject(nome, forKey: "UserName")
        defaults.setInteger(Int(età)!, forKey: "UserAge")

Avvia l’applicazione, scrivi un nome ed un’età nei due campi e premi il tasto salva. Se hai inserito i valori correttamente, i dati verranno salvati nell’NSUserDefaults.

Adesso ti manca solamente il recupero.

Recuperare un’informazione

Recuperare un oggetto dall’NSUserDefaults in Swift è altrettanto semplice quanto salvarlo. C’è solamente un piccolo appunto da fare. Dato che le informazioni vengono recuperate per chiave e si utilizzano dei metodi appositi, come quelli visti per il setInt, setDouble ecc, bisogna stare attenti alla funzione da utilizzare.

S si utilizza uno dei metodi per la lettura, per esempio e si passa una chiave errata o si confonde un metodo per un altro, vengono restituiti dei valori che potrebbero compromettere la tua applicazione.

Prima di farti un esempio, questi sono i metodi da utilizzare:

  • integerForKey(_ :String): Restituisce il valore intero associato alla chiave passata come parametro. Oppure 0 se non esiste il valore o la chiave è errata/non esiste.
  • boolForKey(_: String): Restituisce il valore booleano associato alla chiave. Restituisce false in caso d’errore.
  • doubleForKey(_: String): Restituisce il valore double associato alla chiave. Restituisce 0.0 in caso d’errore.
  • floatForKey(_: String): Restituisce il valore float associato alla chiave. Restituisce 0.0 in caso d’errore.
  • objectForKey(_: String): Restituisce l’AnyObject? associato alla chiave. Restituisce nil in caso d’errore.

I valori di ritorno restituiti in caso d’errore, proprio perché sono valori possibili e non interpretabili, potrebbero portarti a non accorgerti di un probabile problema.

Infatti, immagina di aver assegnato un booleano all’utente per l’utilizzo o meno del Touch ID al posto della password. L’utente passa a true un’impostazione dell’app e questo valore viene correttamente salvato nell’UserDefaults. Se, per errore, fai un boolForKey di una chiave errata, di una che non esiste o di un valore ancora non assegnato verrà sempre restituito false.

Ma false è un valore ammissibile perché può darsi che un utente non passi mai a true quella proprietà. Capisci bene come un errore di disattenzione, proprio perché non segnalato da Xcode, può far accumulare errori che difficilmente noterai (se non in fase di testing o, peggio ancora, in fase di rilascio).

Quindi, se non vuoi provare l’ebrezza di uno sbarco in Normandia di commenti negativi, presta attenzione al codice che scrivi.

Ovviamente uno sbarco non è per niente paragonabile allo scoppia di una bomba atomica. Nel caso di utilizzo errato dell’objectForKey a scoppiare sarà proprio la tua applicazione. Dato che viene restituito nil o un AnyObject, se non correttamente controllato con un optional binding (if let) o con un guard, l’applicazione può crashare con conseguenze disastrose (in questo caso, però, è sicuramente più facile accorgersene).

Il mio consiglio, proprio perché il metodo objectForKey restituisce nil quando non c’è un valore, è quello di cercare di utilizzare sempre il setObject. In questo modo è facile controllare la presenza di valore e prendere le opportune misure. Questo è uno dei casi in cui l’opzionalità del linguaggio Swift ha un’importanza notevole nello sviluppo di un qualsiasi progetto.

Se molti dei concetti che ho citato ti risultano oscuri, ho scritto un corso gratuito sul linguaggio Swift per spiegarti le basi dello sviluppo iOS.

[mailmunch-form id=”101287″]

Ritorniamo all’app che stai realizzando. Salva tutti i dati utilizzando il setObject:

        let defaults = NSUserDefaults.standardUserDefaults()
        
        defaults.setObject(nome, forKey: "UserName")
        defaults.setObject(Int(età)!, forKey: "UserAge")

Adesso, nel metodo viewDidLoad, circoscrivi il recupero dei due oggetti all’interno di un controllo guard:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let defaults = NSUserDefaults.standardUserDefaults()
        
        guard let nome = defaults.objectForKey("UserName") else {
            return
        }
        
        guard let età = defaults.objectForKey("UserAge") else {
            return
        }
        
        print(nome as! String)
        print(età as! Int)
    }

Dato che avevo già salvato il mio nome e la mia età, al successivo avvio, sulla console verranno stampati entrambi a dimostrazione dell’avvenuto recupero dei dati:

Schermata 2016-02-22 alle 13.26.19

Esempio BackgroundColor

Proviamo a creare una sorta di pagina Setting di una applicazione. In questa pagina ci sono tre bottoni che permettono di cambiare il colore di sfondo del ViewController. Una volta che l’utente clicca su uno dei tre bottoni, la preferenza deve essere salvata in memoria ed applicata all’avvio successivo.

Indubbiamente è un problema di memorizzazione delle preferenze dell’utente. Dato che si trattano di piccole quantità di memoria, invece del Core Data opterai per l’NSUserDefaults in Swift.

La pagina che devi creare è la seguente. Se dovessi trovare dei problemi, in fondo alla pagina trovi il download del progetto completo e commentato:

Schermata 2016-02-25 alle 01.42.08

Per il posizionamento dei bottoni ho utilizzato i vincoli di auto layout e le nuovissime stack view. Ogni bottone punta alla stessa IBAction. Dentro l’IBAction di gestione dei bottoni, la func changeColor_clicked, uno switch provvede ad eseguire un codice differente:

    @IBAction func changeColor_clicked(sender: UIButton) {
        switch sender.titleLabel!.text! {
        case "Rosso":
            print("Salvo Rosso")
            break
            
        case "Bianco":
            print("Salvo Bianco")
            break
            
        case "Verde":
            print("Salvo Verde")
            break
            
        default:
            break
        }
    }

Grazie a questa IBAction ed allo switch, salverai nell’NSUserDefaults il colore da salvare in memoria. Come?

Ipotizziamo che l’utente selezioni il tasto “Rosso”. Questo attiverà l’IBAction changeColor_clicked che avvierà lo switch case “Rosso”. All’interno di questo case salverai in memoria il valore “rosso” ad una chiave chiamata, per esempio, “BackgroundColor”. All’avvio successivo l’applicazione leggerà il valore associato a tale chiave e cambierà il colore di sfondo della view.

Semplice no?

Procediamo per step. Prima dello switch, aggiungi un riferimento all’User Defaults standard. Successivamente, nel case “Rosso”, salva la stringa “red_color” alla chiave “BackgroundColor”. La stessa identica operazione eseguila per tutti gli altri case, cambiando per la chiave “BackgroundColor” il valore da salvare. Infine, dovresti avere il seguente codice:

    @IBAction func changeColor_clicked(sender: UIButton) {
        let defaults = NSUserDefaults.standardUserDefaults()
        
        switch sender.titleLabel!.text! {
        case "Rosso":
            print("Salvo Rosso")
            defaults.setObject("red_color", forKey: "BackgroundColor")
            break
            
        case "Bianco":
            print("Salvo Bianco")
            defaults.setObject("white_color", forKey: "BackgroundColor")
            
            break
            
        case "Verde":
            print("Salvo Verde")
            defaults.setObject("green_color", forKey: "BackgroundColor")

            break
            
        default:
            break
        }
    }

Dato che stai salvando delle semplici stringhe e non dei colori, devi far in modo che queste corrispondano realmente a degli oggetti UIColor. Per poter facilmente associare una stringa ad un UIColor, potresti utilizzare un dizionario chiave-valore dove, ogni chiave è il nome del colore (uguale al nome inserito nell’NSUserDefaults) mentre il valore è un oggetto UIColor.

Aggiungi, alla classe ViewController, il seguente dizionario:

class ViewController: UIViewController {
    
    let user_backgroundColor = [
        "red_color" : UIColor(red: 226/255, green: 144/255, blue: 118/255, alpha: 1),
        "green_color" : UIColor(red: 110/255, green: 192/255, blue: 150/255, alpha: 1),
        "white_color" : UIColor(red: 1, green: 1, blue: 1, alpha: 1)
    ]

Dentro il metodo viewDidLoad, che è quello delegato al caricamento delle impostazioni del Controller prima che la View venga renderizzata nello schermo, puoi recuperare il valore salvato nell’NSUserDefaults, controllare che esista (ti ricordo che hai usato un setObject quindi se non viene eseguito ritorna nil il metodo ObjectForKey) ed associarlo al valore del dizionario. Infine, tale valore va passato alla view.backgroundColor del ViewController:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let defaults = NSUserDefaults.standardUserDefaults()
        
        guard let object = defaults.objectForKey("BackgroundColor") else {
            return
        }
        
        self.view.backgroundColor! = self.user_backgroundColor["\(object as! String)"]!

    }

Ti basterà avviare l’applicazione, selezionare un colore e riavviare per vedere applicato il colore scelto nella precedente istanza dell’app:

NSUserDefaults in Swift esempio backgroundColor

Considerazioni

Uno degli altri possibili casi d’utilizzo, che ho trattato nel corso di sviluppo app iOS, è quello di utilizzare l’NSUserDefaults in Swift per visualizzare un tutorial d’anteprima dell’applicazione una sola volta durante l’arco della vita dell’applicazione (il classico tutorial che appare al primo avvio dell’app e poi non esce più).

Ad ogni modo ribadisco il concetto che l’NSUserDefaults è pensato per salvare in memoria piccole quantità di informazioni. Non mi va di fare una lista perché potrebbero essere davvero tanti i casi e le eccezioni. Quindi, se hai un dubbio e non sai se è corretto o meno applicare l’NSUserDefaults in Swift alla tua applicazione, lascia pure un commento. 

Se hai avuto problemi con il tuo progetto, puoi scaricare il mio una volta sbloccato il modulo:

[sociallocker][wpdm_package id=’42806′][/sociallocker]

Da questo tutorial non posso che consigliarti di andare ai seguenti:

Buona Programmazione!

UIImagePickerController in Swift. Recuperare ed importare le immagini dalla Libreria

UIImagePickerController in Swift

Come si recupera un’immagine dalla libreria e la si importa dentro l’applicazione che stai sviluppando?

Moltissime applicazioni lo fanno. Praticamente tutte le app con componenti social ti permettono di, recuperare le immagini che hai scattato e di inserirle dentro l’applicazione per condividerle con gli amici. Altre invece lo utilizzano come strumento di personalizzazione e caratterizzazione dell’applicazione che stai utilizzando.UIImagePickerController in Swift

Per esempio, molti giochi o app, che non hanno una vera e propria parte Social (chat, condivisione ecc) ti permettono di aggiungere un’immagine per la creazione del tuo profilo. Lo scopo?

Lasciare un’impronta personale. Un punto d’incontro tra utente e applicazione.

Qualsiasi sia l’utilità che ti porterà ad importare immagini dentro la tua applicazione, dovrai utilizzare sempre e solamente l’UIImagePickerController. L’oggetto UIImagePickerController in Swift, come la stessa parola suggerisce, offre un accesso veloce alla cartella delle immagini e video.

Ma non solo. L’UIImagePickerController in Swift contiene un’interfaccia preconfezionata e la logica necessaria per recuperare e selezionare le immagini. Questo significa che, una volta creato questo oggetto, dovrai semplicemente selezionare l’immagine o video necessario e premere importa per ritrovartele dentro la tua applicazione iOS.

Abbastanza chiaro, no? Se lo sono stato, passiamo ai fatti e vediamo come implementare l’UIImagePickerController in Swift.

UIImagePickerController

Per prima cosa crea un nuovo progetto iOS Single View Application con il linguaggio Swift. Una volta fatto, passa allo Storyboard ed aggiungi una UIImageView ed un UIButton. Vincolali nel modo che ritieni più appropriato. Infine, crea una IBAction per il bottone (io l’ho chiamata importPhoto_clicked) ed una IBOutlet per l’image view (myImage).

Il bottone lo utilizzerai per aprire l’ImagePicker da cui potrai scegliere l’immagine. Mentre l’image view, una volta presa l’immagine, la mostrerà:

Schermata 2016-02-14 alle 17.05.35

Se non ti ricordi come si creano i vincoli di auto layout, rinfrescati la memoria con l’Introduzione alle interfacce Universali con l’Auto Layout in XcodeSe tutto ciò ti sembra uscito da qualche libro di Harry Potter, forse è meglio che ascolti il mio consiglio e parti da qualcosa di più semplice o dalle basi dello sviluppo.

La mia premessa, l’ho fatta. Adesso continuiamo!

L’oggetto UIImagePickerController, come ti dicevo, fornisce un accesso alla libreria delle tue immagini e video grazie ad un’interfaccia di sistema. L’interfaccia dell’ImagePicker non ha bisogno di essere creata perché è già contenuta all’interno dell’oggetto UIImagePickerController, quindi, l’unica cosa che ti serve è creare un’istanza di tale oggetto all’interno della tua interfaccia.

Nella tua classe ViewController, crea una proprietà di tipo UIImagePickerController opzionale. Infine, istanziala nel metodo viewDidLoad:

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var myImageView: UIImageView!
    
    // creo un riferimento all'UIImagePickerController
    var imagePickerController :UIImagePickerController?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // istanzio l'oggetto PickerController
        self.imagePickerController = UIImagePickerController()
    }

Se classe, opzionalità o proprietà ti suonano come cose nuove vuol dire che ti mancano le basi dello sviluppo. Se ti va, ho scritto un corso gratuito dove spiego le basi della programmazione con il linguaggio Swift.

A questo punto hai un ImagePickerController pronto ad essere utilizzato.

Ma come funziona?

Il funzionamento dell’UIImagePickerController

L’UIImagePickerController ti permette di recuperare le immagini da tre tipi di sorgente. Cioè ti da la possibilità di prendere le immagini direttamente dalla Fotocamera, dagli Album oppure dalla cartella delle Immagini. Non ci sono limitazioni al formato che puoi recuperare. Puoi importare sia video che foto senza nessun problema. Noi ovviamente stiamo studiando solo la possibilità di importare immagini.

La sorgente dell’UIImagePickerController in Swift va definita modificando la proprietà sourceType che è di tipo UIImagePickerControllerSourceType. Il sourceType è un Enum di possibili scelte (Gli Enum li ho spiegato nel corso gratuito). I valori possibili, dunque, sono:

  • .Camera: Se vuoi recuperare ed importare dentro la tua app un’immagine o video scattandola con la fotocamera.
  • .PhotoLibrary: Accederai alla Libreria di iOS dove contieni tutte le foto e video.
  • .PhotoAlbum: Accede alla lista degli Album della libreria.

Una volta definito il sourceType del tuo Image Picker potrai finalmente aprirlo dentro la tua applicazione per permettere all’utente di selezionare l’immagine o video preferito.

Come viene mostrato?

Essendo un Controller, cioè una subclass della UIViewController, dovrai presentarlo utilizzando il metodo presentViewController (sotto vedrai come). Questo metodo farà comparire il Controller sopra l’interfaccia corrente. In pratica, vedrai apparire una interfaccia di selezione (L’ImagePicker) sopra l’attuale ViewController. Appena l’utente avrà selezionato l’immagine, potrà chiudere l’ImagePickerController per ritornare al tuo ViewController (può anche non selezionare immagini).

Una volta che l’utente chiuderà il Picker, verrà invocato il metodo didFinishPickingMediaWithInfo che ti permetterà di accedere alle immagini selezionate.

Ma arriviamoci per step.

Visualizzare l’ImagePicker

Dato che l’UIImagePickerController si trova dentro la classe ViewController, devi rendere quest’ultima delegata alla gestione dei metodi dell’ImagePicker. In più, dovrai aggiungere il delegate UINavigationControllerDelegate per gestire la navigazione dal ViewController all’ImagePickerController. Quindi, nella definizione della classe, aggiungi il protocollo UIImagePickerControllerDelegate e UINavigationControllerDelegate:

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

Una volta fatto dovrai rendere il viewController delegato del UIImagePicker. Nel metodo viewDidLoad, assegna self (cioè il ViewController) alla proprietà delegate del imagePickerController:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // istanzio l'oggetto PickerController
        self.imagePickerController = UIImagePickerController()
        self.imagePickerController!.delegate = self // setto il ViewController come delegato alla gestione dell'imagePicker
    }

Adesso, nella IBAction associata al tuo bottone, aggiungi il seguente codice:

    @IBAction func importPhoto_clicked(sender: UIButton) {
        self.imagePickerController!.allowsEditing = false // blocco la possibilità di editare le foto/video
        self.imagePickerController!.sourceType = .PhotoLibrary // scelgo il sourceType, cioè il luogo in cui pescare le immagini
        
        // visualizzo l'imagePickerController
        presentViewController(self.imagePickerController!, animated: true, completion: nil)
    }

Settando la proprietà allowEditing a false blocchi la possibilità di modificare le immagini durante la selezione. Successivamente viene scelto il sourceType in cui prendere le foto (.PhotoLibrary significa che entrerai nella libreria di sistema). Infine, il metodo presentViewController mostrerà sullo schermo l’imagePickerController.

Se stai sviluppando utilizzando il simulatore di Xcode, fai attenzione perché il sourceType .Camera, per ovvi motivi, non ti permetterà di scattare nessuna foto.

Se vuoi investigare maggiormente questi passaggi o comunque vuoi approfondire lo sviluppo delle applicazioni, puoi seguire il mio corso sullo sviluppo delle applicazioni iOS con Swift.

Adesso avvia l’applicazione. Dovrebbe chiederti di sbloccare l’accesso alla libreria ed, una volta accettato, sarai in grado di visualizzare e selezionare le immagini di sistema:

uiimagePickerController in swift recuperare foto

Tutto sembra andare per il verso giusto. Una volta premuto il bottone, viene presentato L’UIImagePickerController che mostra la cartella delle immagini del simulatore (nella realtà sarà del dispositivo dell’utente). Una volta selezionata un’immagine, oppure se si preme il tasto Cancel, si ritornerà al ViewController della tua applicazione.

Adesso manca solamente poter visualizzare l’immagine recuperata.

Visualizzare l’immagine selezionata dal Picker

Quando l’utente seleziona una immagine, l’UIImagePickerController viene chiuso e contemporaneamente viene invocato il metodo didFinishPickingMediaWithInfo. Tale metodo ha un attributo, chiamato info, che contiene le informazioni selezionate dall’utente.

Ho detto informazioni perché l’attributo info è un dizionario di tipo [NSObject:AnyObject]. Dato che è un dizionario del linguaggio Swift le sue chiavi ti permettono di accedere a dei valori o informazioni dell’immagine. Per esempio puoi utilizzare le seguenti chiavi per:

  • UIImagePickerControllerMediaType: Il valore associato a questa chiave definisce se l’elemento selezionato è un’immagine o un video.
  • UIImagePickerControllerOriginalImage: Puoi recuperare l’immagine selezionata originale e non modificata.
  • UIImagePickerControllerEditedImage: Recupera l’immagine modificata.
  • UIImagePickerControllerCropRect: Restituisce il rettangolo di taglio dell’immagine.
  • UIImagePickerControllerMediaURL: URL del video cioè il percorso all’interno del filesystem in cui si trova il video.
  • UIImagePickerControllerReferenceURL: URL del percorso dell’immagine all’interno della cartella di sistema.
  • UIImagePickerControllerMediaMetadata: Le informazioni tecniche riguardanti l’immagine scattata.
  • UIImagePickerControllerLivePhoto: L’immagine in formato LivePhoto (iOS 9 e iPhone 6S/Plus e successivi).

Detto ciò, impostando il parametro ad info[UIImagePickerControllerOriginalImage], se l’elemento selezionato è un’immagine, il valore associato a tale chiave dovrebbe restituire una UIImage. Questa UIImage può essere passata alla tua ImageView per la visualizzazione:

    // Il metodo viene invocato quando l'utente selezionato un'immagine o video dall'ImagePicker
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        
        // Controllo che l'elemento selezionato sia un'immagine e se lo è faccio il cast in UIImage
        guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
            print("l'elemento selezionato non è un'immagine")
            return
        }
        
        self.myImageView.contentMode = .ScaleToFill // imposto la visualizzazione a ScaleToFill (cioè scala per entrare dentro l'area dell'imageView)
        self.myImageView.image = selectedImage // passo l'immagine selezionata alla myImageView per la visualizzazione
    
        // chiudo l'ImagePickerController
        dismissViewControllerAnimated(true, completion: nil)
    }

Grazie all’istruzione guard, il codice, esegue un controllo sull’esistenza del valore associato alla chiave UIImagePickerControllerOriginalImage e, se esiste, esegue il cast in UIImage (as? UIImage). Se l’oggetto selezionato non dovesse essere una image verrebbe attivato l’else. Una volta passata la selectedImage alla myImageView, il metodo dismissViewControllerAnimated chiude l’UIImagePickerController.

Se adesso avvii l’applicazione dovresti essere in grado di recuperare un’immagine e di visualizzarla nella tua ImageView:

UIImagePickerController in Swift

Solo per completezza. Quando l’utente seleziona il bottone “Cancel”, ovvero quando non vuole prendere nessun’immagine o video, viene invocato il metodo  imagePickerControllerDidCancel. Qui potresti avvisare l’utente del fatto che non ha selezionato un’immagine e forzarlo a sceglierla.

Forzarlo in che senso?

Perché se implementi il metodo e non esegui un dismiss del pickerController, non potrai uscire e ritornare indietro al tuo ViewController. Fai una prova:

    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        print("l'utente ha chiuso l'ImagePickerController")
    }

Se avvii l’applicazione ed entri nel PickerImage, vedrai che premendo il tasto Cancel non potrai tornare indietro. Per farlo ti servirà aggiungere il dismissViewController:

    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        print("l'utente ha chiuso l'ImagePickerController")
        self.dismissViewControllerAnimated(true, completion: nil)
    }

Considerazioni

Adesso che sai implementare l’UIImagePickerController in Swift potrai finalmente importare le immagini o i video dentro le tue future applicazioni iOS. Per esempio, un tutorial che adesso ti consiglio di seguire è quello relativo alla creazione di un’app di Foto Editing con i filtri fotografici.

Download del progetto

[sociallocker][wpdm_package id=’42589′][/sociallocker]

Buona Programmazione!

1# Giveaway: xCoding loves Sketch. Vinci dei fantastici premi! partecipa al contest.

Per festeggiare l’uscita del corso App Design con Sketch 3, noi di xCoding, abbiamo organizzato un contest, sulla nostra pagina Facebook, che ti da la possibilità di vincere uno tra i seguenti fantastici premi:

  1. Apple Magic Mouse 2
  2. iTunes card 50 €
  3. iTunes card 25 €

Leggi il regolamento per saperne di più. Se lo hai già fatto, vai al post del contest.

Regolamento Contest

Il Concorso “xCoding loves Sketch” è sottoposto alle seguenti condizioni:

1. Possono partecipare al Concorso solo gli utenti iscritti alla fan page su Facebook denominata “xCoding.it” e raggiungibile presso
l’indirizzo https://www.facebook.com/xcoding.it/ (d’ora in avanti denominata la Fanpage).

2. Per partecipare al Concorso l’utente deve:

  • a) Mettere un Like alla Fanpage raggiungibile all’indirizzo https://www.facebook.com/xcoding.it/
  • b) Condividere il post del Concorso presente sulla Fanpage, raggiungibile cliccando Qui.
  • c) Scrivere un commento al post del Concorso presente sulla Fanpage: Il testo del commento è libero e frutto del suo personale ingegno. É requisito indispensabile per la partecipazione al concorso che il commento risponda alla domanda “Cos’è per te il design?” e che contenga il tag di almeno 1 (un) amico.
    Es. “-Per me il design è …. con @Alda Rossi, @Paolo Bianchi, @Giulio Verdi”.

3. Non saranno presi in considerazione e saranno pertanto esclusi dal Concorso i commenti privi di tag; l’inserimento di un numero maggiore di tag non darà alcuna priorità o maggiori possibilità di vincita

4. Non saranno presi in considerazione e saranno pertanto esclusi dal Concorso i commenti pubblicati oltre la data di chiusura del Concorso, o inviati secondo modalità differenti da quelle indicate nell’Art.2 del presente Regolamento. Farà fede la data di pubblicazione riportata sulla piattaforma Facebook.

5. Entro 15 giorni dalla scadenza dei termini del Concorso, xCoding.it nominerà un commento vincitore tra quelli partecipanti.

6. Una commissione composta dalla redazione di xCoding.it giudicherà il migliore commento fra quelli pervenuti e stilerà una classifica dei dieci commenti migliori. Il giudizio della commissione è insindacabile. I premi verranno assegnati al primo, secondo, terzo classificato; in caso di rinuncia di questi, i premi verranno assegnati al classificato successivo.

7. L’autore del commento vincitore del primo premio riceverà in premio 1 (un) Magic Mouse 2 prodotto da Apple. Il secondo classificato riceverà in premio una iTunes Card da 50€. Il terzo classificato riceverà in premio una iTunes Card da 25€.

8. I vincitori riceveranno comunicazione della vincita tramite un messaggio privato inviato attraverso la piattaforma Facebook. I vincitori sono tenuti a rispondere entro 15 giorni per accettazione del premio. Se entro tale termine non si riceverà risposta, il premio verrà assegnato al successivo classificato.

9. I premi verranno recapitati ai vincitori tramite corriere espresso all’indirizzo da loro indicato, entro i 6 mesi successivi alla data di chiusura del Concorso.

10. Il Concorso non è soggetto al regolamento di cui al D.P.R. 26 ottobre 2001, n. 430 per gli effetti dell’Art.6 dello stesso: «Non si considerano concorsi e operazioni a premio: a) i concorsi indetti per la produzione di opere letterarie, artistiche o scientifiche, nonché per la presentazione di progetti o studi in ambito commerciale o industriale, nei quali il conferimento del premio all’autore dell’opera prescelta ha carattere di corrispettivo di prestazione d’opera o rappresenta il riconoscimento del merito personale o un titolo d’incoraggiamento nell’interesse della collettività».

11. Ai sensi e per gli effetti degli art. 7 e 12 del Dlgs. n. 70 del 9.4.2003, la Società comunica agli utenti le seguenti informazioni: il promotore del contest è xCoding.it di Giuseppe Sapienza, con sede legale in Via Antonio Pacinotti 10, 95030 Pedara (CT), Italia. P.IVA 05302390876; E-mail: info (at) xcoding.it.

12. xCoding.it è unica responsabile del Concorso, i partecipanti sollevano Facebook da qualsiasi responsabilità. La promozione non è in nessun modo sponsorizzata, appoggiata o amministrata da Facebook né associata a Facebook. Le informazioni sono fornite per la partecipazione a xCoding.it e non a Facebook.

13. I premi sono messi a disposizione direttamente da xCoding.it, la promozione non è in nessun modo sponsorizzata, appoggiata o associata ad Apple.

MessageUI, inviare Email e Messaggi con il linguaggio Swift

MessageUI, inviare Email e Messaggi con il linguaggio Swift

Condivisione! il motivo che dovrebbe spingerti ad implementare un sistema che permetta di inviare email e messaggi con il linguaggio Swift per la tua applicazione iOS.

Sembra una considerazione banale ma, facci caso, la maggior parte delle applicazioni che hanno avuto successo si è diffusa in maniera capillare grazie alla forza di condivisione di questi due strumenti. Su facebook quasi non facciamo caso agli inviti degli amici ad eventi, feste o richieste di download. Ma, quando arriva un messaggio o un email, eccoci là pronti a vedere cosa ci ha mandato il nostro amico più fidato.

Eh si! perché, generalmente, il numero o l’email è un’informazione personale conosciuta solo dagli amici o dai colleghi di lavoro. E chi non vorrebbe seguire, installare o comunque conoscere l’applicazione o il gioco che l’amico o il collega sta utilizzando?

Una delle prime applicazioni ad utilizzare massicciamente la possibilità di inviare email e messaggi è stata sicuramente Whatsapp. Tutti i primi fortunati sono entrati grazie all’invito di un amico o collega.

Forse uno degli strumenti più efficaci a livello di comunicazione e marketing è la condivisione emotiva. Quella che ti spinge, anche inconsapevolmente, a seguire i passi e le scelte dei propri amici.

Quindi, per farla breve, in questo tutorial voglio portati a conoscenza del framework MessageUI. Grazie al framework MessageUI riuscirai ad inviare email e messaggi con il linguaggio Swift dalla tua applicazione iOS.

Sei pronto a diventare uno spammer seriale?

Come progetto base per la tua applicazione, puoi creare un’applicazione simile all’immagine che trovi qui sotto. Il progetto è composto da un ViewController di partenza e due bottoni che portano ad un rispettivo ViewController che nella grafica posseggono gli stessi contenuti. Ovvero una label, una text view ed un bottone. In fondo alla pagina trovi il progetto completo che puoi scaricare nel caso dovessi avere dei problemi.

MessageUI Framework linguaggio swift

Se invece dovessi avere alcuni problemi nella realizzazione dell’interfaccia e non sai da dove cominciare, forse è il caso di partire da qualcosa di più semplice. Per la costruzione delle interfacce se hai aperto il mio progetto, oltre all’auto layout, ho utilizzato le Stack View (introdotte in iOS 9).

Premetto che questo progetto non funziona nel simulatore. Quindi, onde evitare l’autocombustione, devi obbligatoriamente possedere un iPhone con cui poter testare l’applicazione.

Il framework MessageUI

Apple mette a disposizione un Framework per l’invio dei messaggi e delle email. Questo framework prende il nome di MessageUI ed, al suo interno, contiene solamente due classi e due protocolli:

  • MFMailComposeViewController: Ovvero il ViewController per l’interfaccia standard utilizzata per l’invio di una email. La classica pagina che si apre quando crei una nuova email da inviare.
  • MFMessageComposeViewController: Il ViewController con l’interfaccia standard per l’invio di un messaggio.

I restanti due protocolli sono i Delegate, ovvero per l’utilizzo delle sopracitate classi da parte di altri ViewController. Il framework MessageUI non contiene niente di più e niente di meno.

Quindi non ci resta che testare queste due classi.

Inviare una Email con il linguaggio Swift

Per prima cosa spostati nel tuo EmailViewController ed importa il framework MessageUI. Successivamente, devi rendere la classe delegata alla gestione del MFMailComposeViewController, quindi devi implementare il protocollo MFMailComposeViewControllerDelegate. Alla fine, dovresti avere la seguente classe:

import UIKit
import MessageUI

class EmailViewController: UIViewController, MFMailComposeViewControllerDelegate {

    @IBOutlet var field_recipient: UITextField! // la textField per l'acquisizione dell'indirizzo email
    @IBOutlet var textView_message: UITextView! // textView per l'acquisizione del messaggio da inviare
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    // IBAction per l'invio del messaggio email
    @IBAction func sendEmail_clicked(sender: UIButton) {

    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

Nel metodo sendEmail_clicked, che nel mio caso è l’IBAction collegata al bottone dell’interfaccia, prima di utilizzare l’oggetto MFMailComposerViewController, devi controllare che il dispositivo può effettivamente inviare le email. 

Il metodo che controlla se il dispositivo può inviare, o no, una email è il canSendMail(). Il metodo restituisce un booleano, true o false, che stabilisce l’esito del controllo. Nel caso in cui dovesse ritornare false, significherebbe che il dispositivo non è predisposto all’invio di una email (ad esempio non ha account configurati) e, di conseguenza, bisogna avvisare l’utilizzatore ed evitare la creazione dell’oggetto MFMailComposerViewController.

All’interno della IBAction sendEmail_clicked, che ti ricordo è il mio metodo collegato al bottone dell’interfaccia, aggiungi il seguente codice:

    @IBAction func sendEmail_clicked(sender: UIButton) {
        if MFMailComposeViewController.canSendMail() {

        } else {
            print("Errore! non posso inviare email")
            // INVIA UN MESSAGGIO ALL'UTENTE (AD ESEMPIO CON UNA ALERT VIEW)
        }
    }

Nel caso dell’else puoi istanziare una AlertView in modo da avvisare l’utilizzatore dell’errore generato.

Adesso, all’interno dell’if true, puoi istanziare l’oggetto MFMailComposerViewController. Una volta istanziato, devi assegnargli chi sarà il suo delegato (cioè chi sarà a gestirlo, nel tuo caso è il ViewController in cui hai inserito il codice).

if MFMailComposeViewController.canSendMail() {
            
            let mail = MFMailComposeViewController()
            mail.mailComposeDelegate = self

Fatto questo passaggio, devi definire chi sarà il destinatario ed il contenuto dell’email. A tale scopo, puoi utilizzare i metodi:

  • setToRecipients([String]): Che accetta in ingresso un array di stringhe nel caso in cui volessi inviare a più persone la tua email.
  • setSubject(String): Definisce l’oggetto dell’email
  • setMessageBody(message: String, isHTML: Bool): Dove il primo parametro è il messaggio da inviare ed il secondo è un booleano che indica se il messaggio contiene dei tag html oppure no.

Dopo aver settato i campi dell’email, puoi presentare il MailComposer con il presentViewController.

    @IBAction func sendEmail_clicked(sender: UIButton) {
        if MFMailComposeViewController.canSendMail() {
            
            let mail = MFMailComposeViewController()
            mail.mailComposeDelegate = self
            
            mail.setToRecipients([self.field_recipient.text!])
            mail.setSubject("Oggetto di prova")
            mail.setMessageBody(self.textView_message.text, isHTML: false)
            
            self.presentViewController(mail, animated: true, completion: nil)
            
        } else {
            print("Errore! non posso inviare email")
            // INVIA UN MESSAGGIO ALL'UTENTE (AD ESEMPIO CON UNA ALERT VIEW)
        }
    }

Se vuoi testare l’applicazione, ti ricordo che devi collegarla al tuo iPhone reale e selezionarlo da Xcode per il test su dispositivo. Se provi ad avviare il progetto sul simulatore, verrà generato un errore che non potrai risolvere.

MFMailCoposeViewController e inviare email con linguaggio swift
La foto è uno screen del dispositivo. Ti ricordo che il progetto funziona solo su dispositivo reale e non sul simulatore.

Infine, dato che il MailCompose non si chiude quando invii l’email o elimini la bozza, devi aggiungere il metodo del delegate didFinishWithResult. Il metodo didFinishWithResult viene invocato quando l’utente preme sul bottone Invia o Annulla. Per capire il motivo della chiusura del controller ti basta inserire uno switch, e successivamente chiamare il dismissViewController per chiudere definitivamente il MailCompose:

func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {

        switch result{
        
        case MFMailComposeResultCancelled:
            print ("Invio dell'email cancellato dall'utente")
            break
            
        case MFMailComposeResultSaved:
            print ("Email salvata come bozza")
            break
            
        case MFMailComposeResultSent:
            print ("Email inviata correttamente")
            break
            
        case MFMailComposeResultFailed:
            print ("Email non inviata, probabilmente a causa di un errore")
            break
        
        default:
            //questo caso non dovrebbe mai presentarsi!
            break
        
        }
        
        self.dismissViewControllerAnimated(true, completion: nil)
 
    }

Inviare un messaggio con il linguaggio Swift

I passaggi per l’invio di un messaggio sono praticamente gli stessi. I metodi cambiano semplicemente il nome e rimangono uguali nell’implementazione.

Il primo passaggio è sempre quello del check sulla possibilità di invio di un messaggio. Qui il metodo da richiamare si chiama canSendText() e restituisce false nel caso in cui non è possibile inviare un messaggio.

    // IBAction per l'invio del messaggio ad un utente
    @IBAction func sendMessage_clicked(sender: UIButton) {
        if MFMessageComposeViewController.canSendText() {

        } else {
            print("Errore! non posso inviare un messaggio ")
        }
    }

A differenza di un’email, per un messaggio ti basta definire solamente il destinatario e il testo del messaggio. Una volta creato l’oggetto MFMessageComposeViewController e dopo aver assegnato il delegate, puoi riempire le proprietà:

  • recipients: La proprietà è di tipo Array di String e serve a definire i vari destinatari del messaggio.
  • body: La proprietà è di tipo String e rappresenta il messaggio da inviare.
    // IBAction per l'invio del messaggio ad un utente
    @IBAction func sendMessage_clicked(sender: UIButton) {
        let message = MFMessageComposeViewController()
        message.messageComposeDelegate = self
        
        message.recipients = [self.field_recipient.text!]
        message.body = self.textView_message.text

        self.presentViewController(message, animated: true, completion: nil)
    }

Infine, implementa il metodo didFinishWithResult per gestire gli eventi legati alla pressione del tasto Invia o Annulla della finestra di invio di un messaggio:

    func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
        controller.dismissViewControllerAnimated(true, completion: nil)
    }
Inviare un messaggio con il linguaggio swift
Anche in questo caso, l’invio di un messaggio con MFMessageComposeViewController funziona solo su dispositivo reale e non su simulatore.

Considerazioni

Come spero di aver spiegato, inviare Email e Messaggi con il linguaggio Swift è abbastanza semplice e poco complesso. Il motivo reale che mi ha spinto a scrivere questo articolo riguardava più l’acquisizione di nuovi utenti per la propria applicazione.

Inviare una email, meglio ancora un messaggio, è uno strumento potentissimo per pubblicizzare un contenuto della tua applicazione. Spesso sono proprio i contatti telefonici personali che cominciano a scaricare la tua applicazione più per curiosità che per reale necessità.

Ovviamente tra i tuoi contatti ci sarà quello che sarà realmente interessato ed, automaticamente, potrebbe utilizzare la funzione di sponsorizzazione della tua applicazione per invogliare i propri contatti a scaricare la tua applicazione. Ma non voglio annoiarti con storie di questo tipo, anche perché, ci tornerò sicuramente in un nuovo articolo.

Dove andare da qui

Per rimanere in tema di condivisione e acquisizione utenti, ti consiglio di dare un’occhiata a questi articoli:

Download del progetto

[sociallocker][wpdm_package id=’41916′][/sociallocker]

Buona Programmazione!

Notifiche Push Online per iOS con Parse e Swift

Notifiche Push Online per iOS con Parse e Swift

Attenzione! Parse ha deciso di chiudere i battenti a Gennaio 2017. Ho, per tanto, deciso di non trattare più Parse come sistema di supporto. Da ora in avanti utilizzeremo Firebase. Clicca qui per aggiornarti

Se dovessimo eleggere la tecnologia che ha rivoluzionato il modo di interagire con le applicazioni, questa, non può che essere la tecnologia Push.

Le notifiche Push hanno cambiato letteralmente il modo di interagire con il mondo web ed i servizi che esso ci mette a disposizione. Come?

Prima dell’avvento della tecnologia Push, il tuo client per la messaggistica, il client delle email o la stessa applicazione dovevano richiedere ad un servizio web la presenza di nuovi contenuti. In pratica, l’applicazione, ad intervalli periodici, inviava una richiesta al server: “Ehi bello mio, se ne hai, mandami nuove informazioni!” e, quest’ultimo, rispondeva ritornando indietro le informazioni: “Ehi app, ho delle nuove informazioni. Scaricale pure!”.

Se ci rifletti questa procedura poteva causare dei grossi problemi. Ad esempio, un consumo eccessivo delle risorse percHé l’applicazione doveva ogni volta eseguire delle funzioni con ovvie ripercussioni sulla batteria e, spesso e volentieri, il server non aveva nuove informazioni da restituire all’applicazione (quindi l’applicazione eseguiva connessioni inutili).

Con le notifiche Push remote è il server a mandare le informazioni al client. Quindi, il servizio di email o la tua applicazione, non deve più eseguire delle operazioni di richiesta (pull delle informazioni) che consumano moltissima energia e risorse bensì deve semplicemente essere connesso in rete e aspettare che il server gli invii le informazioni (push delle informazioni).

Adesso proviamo a schematizzare meglio il concetto in modo da dare una risposta formale alla domanda: Cosa sono le notifiche Push?

Le notifiche Push sono un sistema di comunicazione tra client, la tua applicazione, ed un server. Con le notifiche Push è il server ad inviare le informazioni al client solo quando strettamente necessario (nuovi contenuti, informazioni importanti, nuove email). In questo modo, l’applicazione o client, deve semplicemente rimanere attiva o in background e connessa alla rete.

Per le applicazioni iOS le notifiche Push funzionano alla stessa maniera?

Se tra il dire ed il fare c’è di mezzo il mare, tra la tua applicazione ed il server c’è di mezzo Apple. Tra il tuo server e la tua applicazione iOS, Apple, mette un sistema chiamato APNs o Apple Push Notification services. Questo APNs permette ad Apple di poter verificare l’attendibilità e la sicurezza delle notifiche e, in più, smistare la notifica su tutti i dispositivi Apple da te in possesso e con la stessa applicazione installata.

Ora! per farla breve è probabile che tu non abbia un server e che ti servano le notifiche push remote per la tua applicazione. Avevo già spiegato come implementare le notifiche locali e, per tanto, ci occuperemo solo della relativa parte online.

Per chi già segue i miei tutorial sa che amo utilizzare un servizio online chiamato Parse. Parse.com è una piattaforma che mette a disposizione diversi servizi da abilitare per la tua applicazione. É gratuito ed è sviluppato da Facebook. I motivi per cui utilizzarlo li ho elencati nel tutorial introduttivo a Parse ed al salvataggio dei dati sul DB che mette a disposizione.

In questo tutorial, quindi, imparerai ad inviare notifiche Push Online per iOS con Parse e Swift. In più imparerai a:

  1. Inviare notifiche push dalla dashboard di Parse
  2. Inviare notifiche push dal dispositivo a tutti i dispositivi
  3. Differenziare le notifiche push in base a delle categorie
  4. Gestire la ricezione delle notifiche push

Prima di cominciare è importante che tu conosca il linguaggio Swift o come creare un’applicazione per iOS e abbia usato Parse Online. Se non lo hai fatto segui il tutorial introduttivo a Parse dove spiego come instaurare una connessione ed utilizzare il suo DB online.

In più, è giusto che te lo dica prima di farti perdere tempo, devi possedere una licenza da sviluppatore ed un iPhone o iPad reale a portata di mano dato che nel simulatore non è possibile testare le notifiche online.

Pronto ad inviare notifiche Push Online per iOS con Parse e Swift? Cominciamo!

Creare un certificato SLL per le notifiche

Come ti dicevo tra il tuo server, in questo caso Parse e la tua applicazione c’è di mezzo l’APNs. Per poter permettere a parse di inviare una notifica alla tua applicazione è necessario che l’APNs conosca la sorgente della notifica e quindi ti autorizzi ad inviare le notifiche.

Per poter dire all’APNs che vuoi inviare delle notifiche da Parse devi creare un certificato. Come i certificati medici, questi comunicano ad Apple che la sorgente delle informazioni è autorevole e quindi può inviare informazioni all’applicazione.

Il processo è un po’ lungo e noioso, arriverai ad un punto in cui vorrai lanciare nell’iperuranio il tuo Mac. Per contro ti dico che se arriverai fino in fondo rimarrai soddisfatto dell’ottimo lavoro che avrai compiuto. Un lavoro più di tenacia che di tecnica e sai bene che le sfide più diff…noiose sono quelle più ardue da superare.

Let’s the dance begin!

Per prima cosa, dal tuo Mac, apri l’applicazione Keychain Access o Accesso Portachiavi (lo trovi nel launchpad o nella cartella delle applicazioni ed è un’applicazione di default). Poi, dalla barra dei menu, seleziona Accesso Portachiavi\Assistente Certificato\Richiedi un certificato da una Autorità…

Certificato Apple per notifiche

Alla schermata che si aprirà, inserisci la tua email, il tuo nome e spunta la casella “Salvata su disco”. Allo step successivo seleziona dove salvare il file che genererà, la scrivania ad esempio e clicca su salva:

Schermata 2015-12-17 alle 10.38.28

App Identifier e certificato

Nella cartella che hai selezionato dovresti trovare un file con estensione .certSigningRequest. A questo punto, il certificato che ti ha rilasciato la società di certificazione (o CA) deve essere caricato sul tuo account di Apple Developer.

Entra nel tuo Apple Developer Member Center e seleziona Certificates, Identifiers & Profiles. Spostati nel menu App ID e seleziona il bottone e a forma di più (+) per aggiungere una nuova applicazione:

Certificati e Apple ID

  1. In App ID descrition puoi scrivere un testo qualsiasi come: “Parse e notifiche Push”. Questo testo non ha relazioni con l’applicazione.
  2. Metti la spunta a Explicit App Id e, in Bundle ID, devi inserire il Bundle Identifier della tua applicazione iOS. Questo valore deve essere assolutamente uguale a quello presente nell’applicazione:

Bundle identifier e App push

Scorri la pagina e, in App Services, seleziona Push Notification. Infine premi su Continue:

App service e Push Notification

Nella pagina del riepilogo, ti verrà comunicato un problema alle Push Notification. Vedrai un pallino arancione con scritto “Configurable”, questo accade perché ancora non hai inserito un certificato valido che permette all’APNs di accettare in ingresso delle notifiche push per la tua applicazione. Clicca su Submit.

Adesso devi inserire il certificato che hai creato poc’anzi. Clicca su App IDs e seleziona la nuova applicazione che hai creato:

iOS_App_IDs_-_Apple_Developer

Un volta seleziona ti apparirà un menu con i servizi abiliti dalla tua applicazione. In fondo, trovi il bottone Edit. Selezionandolo verrai portato in una nuova pagina in cui dovrai inserire il tuo certificato.

Scorri questa pagina fino ad arrivare al servizio di Push Notification. Qui ti chiederà di aggiungere un certificato per la tua applicazione:

Settings_-_iOS_App_IDs_-_Apple_Developer

Nella pagina che si aprirà clicca su Continue e poi su Generate. Arriverai in una pagina in cui ti chiederà di caricare il tuo certificato. Clicca su Choose File e seleziona il certificato che hai creato ad inizio tutorial:

Window_e_Add_-_iOS_Certificates_-_Apple_Developer

Sotto trovi il bottone Generate, cliccalo e alla pagina successiva premi su Download:

Schermata 2015-12-17 alle 13.08.27

Sembra la burocrazia Italiana però, a differenza, questa ha un suo perché. Comunque non ti preoccupare perché ormai hai quasi finito.

Vai nella cartella in cui hai scaricato l’ultimo certificato. Selezionalo e fai doppio click su di esso. Dovrebbe aprirsi il Keychan. Se l’Accesso Portachiavi dovrebbe mandarti un messaggio d’errore dicendoti che non hai i permessi, vicino ai bottoni per chiudere il Keychan, c’è un bottone a forma di lucchetto. Se lo selezioni ed inserisci la password del tuo mac, sbloccherai il caricamento.

Devi caricare il tuo certificato nella sezione Login (nel pannello a sinistra dell’Accesso Portachiavi) e selezionare anche la categoria I mie certificati. Forse ti richiederà nuovamente la password. Inseriscila e trascina il tuo certificato all’interno.

Caricato il certificato, selezionalo con il tasto destro ed esportalo in formato .p12. Ti verrà richiesto di inserire una password per il certificato. Non devi assolutamente inserirla. Lascia vuoto e premi avanti. Ti chiederà la password di sistema ed infine il tuo nuovo certificato verrà salvato nella cartella da te selezionata (da me è Documenti):

Fai molta attenzione perché in questo momento hai creato un certificato che funzionerà esclusivamente con il tuo dispositivo e non per i dispositivi che scaricheranno la tua applicazione.

Per abilitare le notifiche push distribuite devi ripetere tutti questi passaggi e, nella sezione dei service della tua app, dove c’è Push Notification e dove hai creato il certificato, devi crearlo anche per la Production SSL Certificate. Lascio a te il compito di farlo.

Creare il Provisioning Profile

Il Provisioning Profile autentica il tuo dispositivo ad utilizzare l’applicazione. Anche se, da Xcode 7, puoi far partire un’applicazione su un dispositivo non registrato al Developer Program è necessario creare questo certificato per poter far conoscere, all’APNs, chi sta testando il servizio di notifiche push.

Il Provisioning Profile che creerai servirà solo ed esclusivamente per il test nei tuoi dispositivi. L’abilitazione della distribuzione (chiamata Ad Hoc e App Store) la vedrai più avanti.

Se sei uscito, entra nuovamente nel tuo Apple Developer Member Center e seleziona Certificates, Identifiers & Profiles. In fondo alla pagina, nel pannello Provisioning Profile, seleziona All e clicca sul tasto a forma di più (+) in alto a destra:

Window_e_iOS_Provisioning_Profiles_-_Apple_Developer

Ti chiederà di scegliere per quale tipologia di servizio vuoi creare un Provisioning Profile. Come puoi vedere sono presenti due menu. Il primo è Development, che ti farà creare un certificato per i tuoi dispositivi (iOS o tvOS), mentre il secondo servirà per la Distribution della tua applicazione. Quando dovrai pubblicare l’applicazione su App Store, ad esempio, dovrai ricreare un Provisioning Profile per App Store (lo trovi nella parte della distribution).

Dato che tu ti stai avvicinando per la prima volta alle notifiche Push Online per iOS con Parse e Swift, trattiamo la parte di Development. Quindi, seleziona iOS App Development:

Schermata 2015-12-18 alle 00.56.45

Ti schematizzo tutti i passaggi che dovrai fare (sotto trovi l’illustrazione animata):

  1. Nella schermata successiva ti chiederà di selezionare l’App ID a cui associare questo certificato. Devi scegliere l’App ID dell’applicazione che hai creato nel paragrafo precedente (nel mio caso l’avevo chiamata Parse e Notifiche Push). Vai avanti.
  2. Ti verrà chiesto di selezionare l’account da Developer a cui associare tale certificato (devi essere registrato al Dev Program e quindi aver pagato i 99 euro).
  3. Dovrai scegliere i dispositivi che saranno compatibili con tale certificato (se non trovi il tuo, ti basta collegarlo al Mac e far partire un progetto di Xcode sul dispositivo).
  4. Poi devi dare un nome al Profile. Io ho messo “Push e Parse Development Profile”.
  5. Infine dovrai scaricare il tuo certificato. 

Provisioning Profile

Una volta scaricato il profilo, ti basta cliccarci sopra con un doppio click per installarlo (non ti si aprirà nessuna schermata, quindi non entrare nel panico).

Configurare Parse all’invio delle notifiche online

Con i certificati hai finalmente finito.

Adesso è arrivato il momento di cominciare a settare Parse per l’invio delle notifiche online. Il primo step è quello di andare nel tuo pannello Parse. Da qui, spostati nelle impostazioni delle notifiche Push. Da qui potrai scegliere per quale piattaforma abilitare le notifiche e che tipologia di sistema di invio utilizzare.

pannello parse per notifiche push online

Nella parte superiore trovi due opzioni che puoi abilitare:

  • Enable Client Push: Permette di inviare notifiche push online direttamente dal tuo dispositivo. Cioè invii la richiesta di invio di una notifica tramite iphone a parse e lui la smista a tutti gli altri. Utile in fase di test e quando non si ha a disposizione un server.
  • Enable Rest Push: Sblocca l’invio delle notifiche alla ricezione di una richiesta da parte di un tuo servizio REST di un tuo server.

Noi utilizzeremo il primo sistema, cioè l’invio delle notifiche a tutti gli utenti da Client e dal pannello di Parse, quindi spunta la prima opzione.

Infine, nella sezione Apple Push Certificates devi caricare il certificato con estensione .p12 cioè il primo certificato che hai creato. 

Questo è tutto ciò che serve a Parse per inviare delle notifiche push. Con il certificato che hai caricato, quando Parse invierà una notifica all’APN,  manderà anche la firma che hai creato permettendoti di superare il controllo di sicurezza e di raggiungere i vari dispositivi. Adesso manca solamente il setting dell’applicazione per poter finalmente testare l’invio di notifiche push Online per iOS con Parse e Swift.

Preparare l’app a ricevere le notifiche Push da Parse

Siamo quasi arrivati a termine dell’avventura delle notifiche push.

Dovresti aver già creato un progetto iOS perché hai dovuto inserire il suo Bundle Indetifier per la creazione dei Certificati. Se non lo hai fatto, devi ricominciare il tutorial tutto da capo oppure creare un’applicazione con lo stesso Bundle Indetifier che hai utilizzato nei primi paragrafi.

Il primo step è quello di associare l’account da sviluppatore al progetto. Seleziona l’icona del progetto ed associa il tuo account nel campo Team:

Provisioning profile associazione Xcode progetto

Ora tocca al Provisioning Profile. Spostati nel campo Build Phases e scendi fino alle impostazioni di Code Signing. Qui, apri il menu a tendina Code Signing Identity e, in ogni campo, seleziona il tuo account da sviluppatore. Subito sotto, nel menu a tendina Provisioning Profile, seleziona il provisioning profile che hai creato nel paragrafo precedente (ha lo stesso nome ed è quel certificato che hai attivato con doppio click) per tutte le opzioni:

Provisioning Profile per applicazione iOS e notifiche

Nel caso in cui dovrai rilasciare la tua applicazione al pubblico, ti ricordo, che dovrai creare un ulteriore certificato impostato come Release e, di conseguenza, dovrai inserire quest’ultimo nel campo Release del Provisioning Profile.

Gli stessi identici passaggi, che hai fatto per il Target, devono essere eseguiti per l’intero progetto. Quindi cambia pannello dal target all’intero progetto e assegna gli stessi valori:

provisioning profile notifiche push parse

Adesso spostati nell’AppDelegate.swift. Importa il framework Parse e, nel metodo didFinishLaunchingWithOptions attiva la connessione alla tua Parse Application. I passaggi sono gli stessi che ho spiegato nel primo tutorial a Parse.

Successivamente bisogna sbloccare l’utilizzo delle notifiche per l’applicazione, quindi inserisci anche la chiamata al metodo registerUserNotificationSettings in modo da far comparire il banner per l’accettazione delle notifiche all’avvio dell’applicazione.

Infine il tuo didFinishLaunchingWithOptions dovrebbe essere simile a questo:

import UIKit
import Parse

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        
        Parse.setApplicationId("laTuaApplicationID", clientKey: "laTuaClientKey")
        
        let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        
        return true
    }

Nel caso in cui dovessi avere dei problemi ti ricordo che puoi trovare

Attivare la ricezione di notifiche remote

Per poter attivare le notifiche push remote è necessario che l’applicazioni mandi una richiesta all’APNs. La richiesta deve essere mandata nel metodo del AppDelegate didRegisterUserNotificationSettings che sarà attivato non appena l’utente accetterà l’utilizzo delle notifiche (il codice che hai inserito poc’anzi). Quindi dentro la classe AppDelegate inserisci il metodo didRegisterUserNotificationSettings:

    func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
        application.registerForRemoteNotifications()
    }

Dentro il metodo chiamiamo la funzione registerForRemoteNotifications che invia all’APNs la richiesta per poter ricevere notifiche push. Se l’APNs conferma l’applicazione, cioè verifica che i certificati siano in regola, allora viene invocato il metodo del AppDelegate didRegisterForRemoteNotificationsWithDeviceToken.

Il DeviceToken è il codice che identifica il tuo dispositivo nei confronti dell’APNs. Questo codice deve anche essere comunicato a Parse in modo che lui sa a quale dispositivo dover inviare le notifiche. In pratica l’APNs conosce il tuo device token, tu lo comunichi anche a Parse e quest’ultimo poi dirà all’APNs: “senti, io devo inviare una notifica a questo device token, posso farlo?” e l’APNs, dato che ha già salvato il device, risponderà di si.

    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
        let installation = PFInstallation.currentInstallation()
        installation.setDeviceTokenFromData(deviceToken)
        installation.saveInBackground()
        print("device token installato correttamente")
    }

La registrazione del device token a Parse avviene tramite l’invocazione del metodo setDeviceTokenFromData per l’oggetto PFInstallation. Infine viene salvato il tutto con il saveInBackground.

Registrazione fallita all’APNs

Se il metodo registerForRemoteNotification dovesse fallire, non verrà mai invocato il didRegisterForRemoteNotificationWithDeviceToken bensì, verrà chiamato il didFailToRegisterForRemoteNotificationWithError dove potrai gestire l’errore inviando un messaggio all’utente:

    func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
        print("Registrazione all'APNs fallita con errore: \(error)")
    }

In questo caso ti consiglio di rivedere un po’ tutti i passaggi del tutorial perché sicuramente avrai saltato qualche passaggio.

didReceiveRemoteNotification, la ricezione delle notifiche

Quando l’applicazione ricevere è attiva e riceve una notifica, viene invocato il metodo didReceiveRemoteNotification dell’AppDelegate. La proprietà userInfo contiene le informazioni riguardanti la notifica come, ad esempio, il contenuto del messaggio ricevuto (in formato JSON).

    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
        print("Notifica Remota ricevuta")
        PFPush.handlePush(userInfo)
        print(userInfo)
    }

Il metodo si attiva esclusivamente quando l’applicazione è attiva e non si trova in Background.

Se, invece, la tua applicazione si trova nel background e vuoi gestire una notifica remota, devi utilizzare il metodo didReceiveRemoteNotification completionHandler:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

}

Al solito, la proprietà userInfo contiene le informazioni sulla notifica (dato che viene inviato un JSON le chiavi del dizionario puoi estrapolarle convertendo NSObject in String) mentre, grazie al completionHandler, hai la possibilità di eseguire delle operazioni durante il passaggio dalla modalità di background a quella di foreground (come ad esempio il download di immagini passate come id dalla notifica di parse).

Per maggiori informazioni ti consiglio di guardare la documentazione ufficiale di Parse.com. Io tratterò questi argomenti in altri tutorial dato che già in questo c’è troppa carne sul fuoco.

Inviare una notifica Push da Parse

Adesso hai tutto pronto per l’invio e la ricezione di una notifica Push da Parse.

Il primo passo che devi fare è quello di collegare il tuo dispositivo iOS ad Xcode. Ti ricordo che non puoi testare la ricezione di notifiche push dal simulatore, bensì ti serve obbligatoriamente un dispositivo reale. Una volta collegato, seleziona il target da Xcode e avvia l’applicazione.

Poi torna sulla dashboard di Parse.com, seleziona la tua app e spostati nella selezione Push. Nella pagina principale vedrai la lista delle notifiche inviate (se hai una nuova app dovrebbe essere vuota). In alto a destra c’è il bottone Send a Push che ti permetterà di inviare una notifica. Cliccalo:

Parse.com dashboard e push notification

Ci sono diversi campi interessanti. Il primo che ti si presenterà sarà quello relativo alla Audience. Parse ti da la possibilità di dividere il pubblico della tua applicazione in categorie, da qui puoi selezionare a quale categoria inviare le notifiche (per esempio ai solo membri VIP della tua app).

Di default dovrebbe esserci l’Audience Everyone. Dovrebbe anche esserci un utente (la Size dovrebbe essere 1) cioè il tuo dispositivo dato che prima dovresti aver avviato l’applicazione sul tuo dispositivo.

Più in basso ci sono diverse opzioni tra cui la possibilità di creare test A/B (utili per scegliere quale tipo di notifica ha più efficacia) ed altre impostazioni per la schedulazione della notifica (invia immediatamente o invia ad una data precisa).

Infine c’è il campo per compilare i dati della tua notifica. Per inviare la notifica devi obbligatoriamente inserire un testo:

invio notifiche push con parse.com

Infine, potrai premere il tuo bel tasto Send push che invierà la notifica a tutti i dispositivi della tua Audience. Sul tuo iPhone di conseguenza dovrebbe comparire l’alert ed in console dovresti vedere i vari print del messaggio ricevuto.

Schermata 2016-01-05 alle 11.51.18Notifiche Push dal dispositivo

Se invece vuoi testare l’invio delle notifiche push direttamente dal dispositivo, puoi utilizzare il seguente codice:

let push = PFPush()
push.setMessage("Questa è una notifica di prova dal dispositivo!")
push.sendPushInBackground()

Nel mio progetto, ad esempio, ho associato questo codice alla IBAction di un bottone:

Schermata 2016-01-05 alle 11.56.57

Se adesso vai nella dashboard di Parse vedrai la comparsa di una nuova riga nella lista delle notifiche inviate.

Inviare le notifiche ad un canale

Per registrare un utente ad un canale ben preciso, cioè ad un gruppo di persone che riceveranno solo determinate notifiche, puoi utilizzare il seguente codice:

let currentInstallation = PFInstallation.currentInstallation()
currentInstallation.addUniqueObject("SwiftDev", forKey: "channels")
currentInstallation.saveInBackground()

Questo farà si che la currentInstallation, cioè il device che stai utilizzando, venga iscritto al canale SwiftDev. Se adesso torni su Parse e vai su Core\Browser\Installation vedrai che nel campo “channels” sarà comparsa la stringa SwiftDev:

Channel per notifiche push mirate

Questo ti permette di mirare le tue notifiche solo a determinati iscritti alle varie sezioni della tua applicazioni. Non è cosa da poco, in questo modo puoi sfoltire di gran lunga il numero di utenti che non sono interessati a determinate notizie o non sono iscritte a versioni vip della tua applicazione.

Infine, puoi inviare una notifica ad un channels aggiungendo una semplice riga di codice:

        let push = PFPush()
        push.setChannel("SwiftDev")
        push.setMessage("Questa è una notifica solo per gli iscritti a SwiftDev!")
        push.sendPushInBackground()

Puoi anche inviare notifiche a più di un canale, semplicemente aggiungendo un array di String al metodo setChannels (invece che setChannel).

Considerazioni

Con questo concludo il tutorial riguardante l’invio delle Notifiche Push Online per iOS con Parse e Swift. Con Parse.com le possibilità di personalizzare le notifiche sono quasi infinite, per tale ragione ho preferito trattare solo i primi argomenti principali in questo tutorial. Ne arriveranno altri più avanti in cui ti farò vedere come gestire in maniera avanzata la ricezione delle notifiche.

Per ora, scervellati a gestire i certificati ed a configurare correttamente l’applicazione!

In più, ti consiglio di dare una bella lettura alla documentazione ufficiale dato che è semplicissima da capire.

Detto ciò, gli altri tutorial che ti suggerisco sono i seguenti:

Infine se vuoi scaricare il mio progetto per vedere come ho scritto il codice, sblocca il seguente form:

[sociallocker][wpdm_package id=’40898′][/sociallocker]

Buona Programmazione!

2016: Anno nuovo, vit… obiettivi nuovi. Scopri la nostra futura linea editoriale

Com’è che si dice? Anno nuovo, vi… obiettivi nuovi?

Puntualmente, ogni anno, si cerca di scrivere quello che sarà il futuro del nuovo anno. C’è che si accontenta e continua a seguire il percorso intrapreso nell’anno precedente e c’è chi, invece, da una svolta alla sua vita.

Noi di xCoding.it vogliamo intraprendere la via del cambiamento e dare un netto taglio con l’anno precedente riscrivendo nuovamente, non la nostra vita, ma i nostri obiettivi.

Se nel 2015 il nostro obiettivo è stato quello di condividere le nostre conoscenze in materia di sviluppo applicazioni, quest’anno vogliamo andare oltre. Perciò è con immenso piacere che ti annuncio che dalla prima settimana del 2016, io e gli altri Dev, daremo vita ad una rubrica settimanale. Con cadenza regolare, gli autori, scriveranno nuovi articoli che ti accompagneranno nel mondo dello sviluppo applicazioni, del design e del marketing (sempre rimanendo sul main focus delle applicazioni).

L’intento è quello di fornire un’esperienza completa a 360°. Noi di xCoding non lasciamo indietro nessuno, anzi, vogliamo accompagnarti nel tuo viaggio: dai primi passi alla creazione di splendide app e, perché no, alla fondazione di un vero e proprio business.

Quand’è che cominceremo?

Come tutti i progetti che si rispettano, partiremo da Lunedì. Quindi già da domani, 4 Gennaio, potrai leggere uno dei nuovi articoli e tutorial della nostra nuova linea editoriale.

Buona Programmazione!