Nel precedente tutorial, abbiamo esplorato i fondamenti dello sviluppo di WatchKit. Abbiamo creato un progetto in Xcode, aggiunto un'applicazione WatchKit e creato un'interfaccia utente di base.
L'interfaccia utente della nostra applicazione WatchKit visualizza attualmente dati statici. A meno che non si viva nel deserto, non è molto utile per un'applicazione meteorologica. In questo tutorial, inseriremo l'interfaccia utente con i dati e creeremo alcune azioni.
WKInterfaceDate
Prima di popolare l'interfaccia utente con i dati, dobbiamo apportare una piccola modifica. Nel precedente tutorial, abbiamo aggiunto un WKInterfaceDate
istanza al gruppo in basso per visualizzare l'ora e la data correnti. Sarebbe più utile, tuttavia, visualizzare l'ora e la data dei dati che stiamo visualizzando. La ragione di questo cambiamento diventerà chiara in pochi istanti.
Aperto Interface.storyboard, Rimuovi il WKInterfaceDate
istanza nel gruppo in basso e sostituirlo con a WKInterfaceLabel
esempio. Imposta l'etichetta Larghezza attribuire a Relativo al contenitore e l'etichetta Allineamento allineato a destra.
Per aggiornare l'interfaccia utente con i dati dinamici, dobbiamo creare alcuni punti vendita nel InterfaceController
classe. Apri lo storyboard nell'editor principale e InterfaceController.swift nel Assistente editore sulla destra. Seleziona l'etichetta in alto nel primo gruppo e Control-trascinamento dall'etichetta al InterfaceController
classe per creare uno sbocco. Dai un nome alla presa locationLabel
.
Ripeti questi passaggi per le altre etichette, nominandole temperatureLabel
e dateLabel
rispettivamente. Questo è ciò che InterfaceController
la classe dovrebbe assomigliare quando hai finito.
import WatchKit import Foundation class InterfaceController: WKInterfaceController @IBOutlet weak var dateLabel: WKInterfaceLabel! @IBOutlet weak var locationLabel: WKInterfaceLabel! @IBOutlet weak var temperatureLabel: WKInterfaceLabel! override func awakeWithContext (context: AnyObject?) super.awakeWithContext (context) override func willActivate () // Questo metodo viene chiamato quando il controller di visualizzazione watch sta per essere visibile all'utente super.willActivate () override func didDeactivate ( ) // Questo metodo viene chiamato quando il controller di visualizzazione dell'orologio non è più visibile super.didDeactivate ()
Ora potrebbe essere un buon momento per dare un'occhiata più da vicino all'implementazione del InterfaceController
classe. Nel precedente tutorial, l'ho menzionato InterfaceController
eredita da WKInterfaceController
. A prima vista, può sembrare che a WKInterfaceController
l'istanza si comporta come a UIViewController
esempio, ma abbiamo anche imparato nel tutorial precedente che ci sono alcune differenze chiave.
Per aiutarci, Xcode ha popolato il InterfaceController
classe con tre metodi sovrascritti. È importante capire quando viene invocato ciascun metodo e per cosa può o deve essere utilizzato.
awakeWithContect (_ :)
Nel awakeWithContext (_ :)
metodo, si imposta e si inizializza il controller dell'interfaccia. Forse ti starai chiedendo in che modo differisce da dentro
metodo. Il awakeWithContext (_ :)
il metodo viene richiamato dopo l'inizializzazione del controller dell'interfaccia. Il metodo accetta un parametro, un oggetto di contesto che consente ai controller di interfaccia di passare le informazioni l'un l'altro. Questo è l'approccio raccomandato per passare informazioni attraverso scene, cioè controller di interfaccia.
willActivate
Il willActivate
il metodo è simile al viewWillAppear (_ :)
metodo del UIViewController
classe. Il willActivate
il metodo viene richiamato prima che l'interfaccia utente del controller di interfaccia sia presentata all'utente. È ideale per modificare l'interfaccia utente prima che venga presentata all'utente.
didDeactivate
Il didDeactivate
metodo è la controparte del willActivate
metodo e viene richiamato quando la scena del controller dell'interfaccia è stata rimossa. Qualsiasi codice di pulizia va in questo metodo. Questo metodo è simile al viewDidDisappear (_ :)
metodo trovato nel UIViewController
classe.
Tenendo presente quanto sopra, possiamo iniziare a caricare i dati e aggiornare l'interfaccia utente della nostra applicazione WatchKit. Iniziamo con il caricamento dei dati meteo.
Potresti pensare che il prossimo passo riguardi una chiamata API a un servizio meteo, ma non è questo il caso. Se stessimo costruendo un'applicazione iOS, avresti ragione. Tuttavia, stiamo creando un'applicazione WatchKit.
Non è consigliabile effettuare chiamate API complesse per recuperare i dati per popolare l'interfaccia utente di un'applicazione WatchKit. Anche se Apple non menziona esplicitamente questo nella documentazione, un ingegnere Apple ha menzionato questa best practice non scritta nei forum degli sviluppatori Apple.
L'applicazione WatchKit fa parte di un'applicazione iOS ed è l'applicazione iOS che è responsabile del recupero dei dati da un back-end remoto. Ci sono diversi approcci che possiamo fare per fare ciò, mentre il recupero dei dati è una buona scelta. In questo tutorial, tuttavia, non ci concentreremo su questo aspetto.
Al contrario, aggiungeremo dati fittizi al pacchetto dell'estensione WatchKit e caricarli nel file awakeWithContext (_ :)
metodo che abbiamo discusso in precedenza.
Crea un file vuoto selezionando Nuovo> File ... dal File menu. Scegliere Vuoto dal iOS> Altro sezione e nominare il file weather.json. Ricontrolla che stai aggiungendo il file al Estensione RainDrop WatchKit. Non trascurare questo piccolo ma importante dettaglio. Compila il file con i seguenti dati.
"locations": ["location": "Cupertino", "temperatura": 24, "timestamp": 1427429751, "location": "London", "temperature": 11, "timestamp": 1427429751, "location": "Paris", "temperature": 9, "timestamp": 1427429751, "location": "Brussels", "temperature": 11, "timestamp": 1427429751]
La condivisione dei dati tra l'applicazione iOS e l'applicazione WatchKit è un argomento importante. Tuttavia, questo tutorial si concentra su come far funzionare la tua prima applicazione WatchKit. In un futuro tutorial, mi concentrerò sulla condivisione dei dati tra un'applicazione iOS e un'applicazione WatchKit.
Anche se non copriremo la condivisione dei dati in questo tutorial, è importante sapere che l'applicazione iOS e l'estensione WatchKit non condividono una sandbox. Entrambi gli obiettivi hanno una propria sandbox e questo è ciò che rende i dati di condivisione meno banali di quanto sembri.
Per condividere i dati tra iOS e l'applicazione WatchKit, è necessario sfruttare i gruppi di app. Ma questo è un argomento per un futuro tutorial.
Swift è un ottimo linguaggio, ma alcuni compiti sono più semplici in Objective-C che in Swift. Gestire JSON, ad esempio, è una di queste attività. Per semplificare questo compito, ho scelto di sfruttare la famosa libreria SwiftyJSON.
Scarica il repository da GitHub, decomprimi l'archivio e aggiungi SwiftyJSON.swift al Estensione RainDrop WatchKit gruppo. Questo file si trova nel fonte cartella dell'archivio. Ricontrolla quello SwiftyJSON.swift è aggiunto il Estensione RainDrop WatchKit bersaglio.
WeatherData
Per semplificare il lavoro con i dati meteo memorizzati in weather.json, creeremo una struttura chiamata WeatherData. Selezionare Nuovo> File ... a partire dal il File menu, scegliere Swift File dal iOS> Origine sezione e nominare il file WeatherData. Assicurati che il file sia aggiunto al Estensione RainDrop WatchKit bersaglio.
L'implementazione del WeatherData
la struttura è breve e semplice La struttura definisce tre proprietà costanti, Data
, Posizione
, e temperatura
.
import Foundation struct WeatherData let date: NSDate let location: String let temperature: Double
Perché il valore della temperatura di weather.json è in Celcius, implementiamo anche una proprietà calcolata fahrenheit
per una facile conversione tra Celcius e Fahrenheit.
var fahrentheit: Double temperatura di ritorno * (9/5) + 32
Definiamo anche due metodi di supporto toCelciusString
e toFahrenheitString
per rendere più facile la formattazione dei valori di temperatura. Non ami l'interpolazione a corda di Swift?
func toCelciusString () -> String return "\ (temperatura) ° C" func aFahrenheitString () -> String return "\ (fahrentheit) ° F"
Come ho detto, l'implementazione del WeatherData
la struttura è breve e semplice Questo è l'aspetto che dovrebbe avere l'implementazione.
import Foundation struct WeatherData let date: NSDate let location: String let temperatura: Double var fahrentheit: Double temperatura di ritorno * (9/5) + 32 func toCelciusString () -> String return "\ (temperatura) ° C" func toFahrenheitString () -> String return "\ (fahrentheit) ° F"
Prima di caricare i dati da weather.json, dobbiamo dichiarare una proprietà per la memorizzazione dei dati meteorologici. La proprietà, weatherData
, è di tipo [WeatherData]
e conterrà il contenuto di weather.json come esempi del WeatherData
struttura.
var weatherData: [WeatherData] = []
Per facilità d'uso, dichiariamo anche una proprietà calcolata, tempo metereologico
, che ci dà accesso al primo elemento del weatherData
array. Sono i dati di questo WeatherData
istanza che mostreremo nel controller dell'interfaccia. Riuscite a indovinare perché dobbiamo dichiarare il tempo metereologico
proprietà come facoltativo?
var weather: WeatherData? return weatherData.first
Carichiamo i dati da weather.json nel awakeWithContext (_ :)
metodo. Per mantenere l'implementazione pulita, invochiamo un metodo di supporto denominato loadWeatherData
.
override func awakeWithContext (context: AnyObject?) super.awakeWithContext (context) // Carica dati meteo loadWeatherData ()
L'implementazione di loadWeatherData
è probabilmente lo snippet di codice più scoraggiante che vedremo in questo tutorial. Come ho detto, l'analisi di JSON non è banale in Swift. Fortunatamente, SwiftyJSON fa la maggior parte del lavoro pesante per noi.
func loadWeatherData () let path = NSBundle.mainBundle (). pathForResource ("weather", ofType: "json") se lasciato path = path let data = NSData (contentsOfFile: path) se let data = data let weatherData = JSON (data: data) lascia location = weatherData ["locations"]. Array se let locations = locations per posizione in locations let timestamp = location ["timestamp"]. let date = NSDate (timeIntervalSinceReferenceDate: timestamp) lascia model = WeatherData (data: date, location: location ["posizione"]. stringa !, temperatura: posizione ["temperatura"] .doppia!) self.weatherData.append (modello)
Otteniamo il percorso per weather.json e carica il suo contenuto come un NSData
oggetto. Usiamo SwiftyJSON per analizzare il JSON, passando in NSData
oggetto. Otteniamo un riferimento alla matrice per la chiave posizioni e loop su ogni posizione.
Normalizziamo i dati meteorologici convertendo il timestamp in un NSDate
istanza e inizializzare a WeatherData
oggetto. Infine, aggiungiamo il WeatherData
oggetto al weatherData
schieramento.
Spero tu accetti che l'implementazione non è poi così difficile. Poiché Swift ci obbliga a fare un numero di controlli, l'implementazione sembra più complessa di quanto non sia in realtà.
Con i dati meteo pronti all'uso, è ora di aggiornare l'interfaccia utente. Come ho spiegato in precedenza, l'aggiornamento dell'interfaccia utente deve avvenire nel willActivate
metodo. Diamo un'occhiata all'implementazione di questo metodo.
override func willActivate () // Questo metodo viene chiamato quando il controller di visualizzazione watch sta per essere visibile all'utente super.willActivate () se let weather = self.weather locationLabel.setText (weather.location) // Aggiorna etichetta di temperatura self .updateTemperatureLabel () // Aggiorna etichetta data self.updateDateLabel ()
Dopo aver invocato il willActivate
metodo della superclasse, scartiamo il valore memorizzato nel file tempo metereologico
proprietà. Per aggiornare l'etichetta della posizione, invochiamo setText
, passando il valore memorizzato nel Posizione
proprietà del tempo metereologico
oggetto. Per aggiornare le etichette di temperatura e data, invochiamo due metodi di supporto. Preferisco mantenere il willActivate
metodo breve e conciso, e, cosa più importante, non mi piace ripetere me stesso.
Prima di esaminare questi metodi di supporto, è necessario sapere se la temperatura deve essere visualizzata in Celsius o Fahrenheit. Per risolvere questo problema, dichiarare una proprietà, Celsius
, di tipo Bool
e impostare il suo valore iniziale su vero
.
var celcius: Bool = true
L'implementazione di updateTemperatureLabel
è facile da capire. Scartiamo il valore memorizzato in modo sicuro tempo metereologico
e aggiornare l'etichetta della temperatura in base al valore di Celsius
. Come puoi vedere, i due metodi di supporto di WeatherData
la struttura che abbiamo creato in precedenza è utile.
func updateTemperatureLabel () if let weather = self.weather if self.celcius temperatureLabel.setText (weather.toCelciusString ()) else temperatureLabel.setText (weather.toFahrenheitString ())
L'implementazione di updateDateLabel
non è nemmeno difficile. Inizializziamo un NSDateFormatter
esempio, impostalo formato data
proprietà e convertire la data del tempo metereologico
oggetto chiamando stringFromDate (_ :)
sul dateFormatter
oggetto. Questo valore viene utilizzato per aggiornare l'etichetta della data.
func updateDateLabel () var data: NSDate = NSDate () // Initialize Date Formatter let dateFormattter = NSDateFormatter () // Configure Date Formatter dateFormattter.dateFormat = "d / MM HH: mm" se let weather = self.weather date = weather.date // Aggiorna data Etichetta dateLabel.setText (dateFormattter.stringFromDate (date))
Costruisci ed esegui l'applicazione per vedere il risultato. L'interfaccia utente dovrebbe ora essere popolata con i dati da weather.json.
Questo sembra buono. Ma non sarebbe bello se avessimo aggiunto il supporto sia a Celcius che a Fahrenheit? Questo è facile da fare poiché abbiamo già posto la maggior parte delle basi.
Se la forza dell'utente tocca l'interfaccia utente di un controller dell'interfaccia utente, viene visualizzato un menu. Naturalmente, funziona solo se è disponibile un menu. Vediamo come funziona.
Aperto Interface.storyboard e aggiungere un menu al Controller di interfaccia nel Struttura del documento sulla sinistra. Per impostazione predefinita, un menu ha una voce di menu. Abbiamo bisogno di due voci di menu, quindi aggiungi un'altra voce di menu al menu.
Si noti che il menu e le relative voci di menu non sono visibili nell'interfaccia utente. Questo non è un problema poiché non possiamo configurare il layout del menu. Quello che possiamo cambiare sono il testo di una voce di menu e la sua immagine. Capirai meglio cosa significa quando presentiamo il menu.
Seleziona la voce del menu in alto, apri il Ispettore degli attributi, impostato Titolo a Celsius, e Immagine a Accettare. Seleziona la voce del menu in basso e imposta Titolo a Fahrenheit e Immagine a Accettare.
Avanti, aperto InterfaceController.swift nel Assistente editore sulla destra. Control-trascinamento dalla voce del menu in alto a InterfaceController.swift e creare un'azione chiamata toCelcius
. Ripeti questo passaggio per la voce del menu in basso, creando un'azione chiamata toFahrenheit
.
L'implementazione di queste azioni è breve. Nel toCelcius
, controlliamo se il Celsius
la proprietà è impostata su falso
, e, se lo è, impostiamo la proprietà su vero
. Nel toFahrenheit
, controlliamo se il Celsius
la proprietà è impostata su vero
, e, se lo è, impostiamo la proprietà su falso
.
@IBAction func toCelcius () if! Self.celcius self.celcius = true @IBAction func aFahrenheit () if self.celcius self.celcius = false
Se il valore di Celsius
modifiche, abbiamo bisogno di aggiornare l'interfaccia utente. Quale modo migliore per realizzare questo implementando un osservatore di proprietà sul Celsius
proprietà. Dobbiamo solo implementare a didSet
osservatore di proprietà.
var celcius: Bool = true didSet if celcius! = oldValue updateTemperatureLabel ()
L'unico dettaglio degno di nota è che l'interfaccia utente viene aggiornata solo se il valore di Celsius
ha fatto cambiare. L'aggiornamento dell'interfaccia utente è semplice come la chiamata updateTemperatureLabel
. Costruisci ed esegui l'applicazione WatchKit in iOS Simulator per testare il menu.
Vale la pena ricordare che il simulatore iOS imita la reattività di un dispositivo fisico. Cosa significa? Ricorda che l'estensione WatchKit gira su un iPhone mentre l'applicazione WatchKit gira su un Apple Watch. Quando l'utente tocca una voce di menu, l'evento tattile viene inviato tramite una connessione Bluetooth all'iPhone. L'estensione WatchKit elabora l'evento e invia eventuali aggiornamenti indietro all'Apple Watch. Questa comunicazione è piuttosto veloce, ma non è veloce come se l'estensione e l'applicazione dovessero essere eseguite sullo stesso dispositivo. Questo breve ritardo è imitato da iOS Simulator per aiutare gli sviluppatori a farsi un'idea delle prestazioni.
Dopo aver spostato la testa sull'architettura di un'applicazione WatchKit, diventa molto più facile comprendere le possibilità e i limiti della prima generazione di applicazioni WatchKit. In questo tutorial, abbiamo coperto solo gli elementi essenziali dello sviluppo di WatchKit. C'è molto altro da scoprire ed esplorare. Rimanete sintonizzati.