dynamische iphone-anwendungen entwickeln. anwendungsentwicklung mit html, css und javascript
TRANSCRIPT
Dynamische iPhone-Anwendungen entwickeln
Lee S. Ba rney
Dynamische iPhone-Anwendungen entwickeln
.. ~ .. ADDISON-W ESLEY
An impri nt of Pearson Education
München • Boston • San Francisco • Harlow, England
Don Mills, Ontario • Sydney • Mexico City
Madrid • Amsterdam
Bibl iografische Information der Deutschen Nationalbibl iothek
Die Deut sche Nationalbibliot hek verzeichnet diese Publikation in der Deutschen Nationalbibl iografie;
det aillierte bibl iografische Dat en sind im Int ernet über http:/ /dnb.d-nb.de abrufbar.
Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuel len Patentschutz
veröffentl icht. Warennamen werden ohne Gewährleistung der fre ien Verwendbarkeit benutzt.
Bei der Zusammenst el lung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren
können für feh lerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch
irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind
Verlag und Herausgeber dankbar.
Autorisierte Übersetzung der amerikanischen Orig inalausgabe: "Developing Hybrid Applications forthe iPhone".
Al le Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig.
Fast al le Hard- und Softwarebezeichnungen und weitere Stichworte und sonstige Angaben, die in d iesem Buch verwendet werden, sind als eingetragene Marken geschützt.
Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht,
w ird das ®-Symbol in d iesem Buch nicht verwendet.
Authorized translation from the English language edit ion, entit led "Developing Hybrid Web Applications"
by Barney, lee S., published by Pearson Education, lnc, publishing as Addison Wesley Professional,
Copyright© 2009 All r ights reserved. No part ofthis book may be reproduced ortransmitted in anyform or by any means,
electronic or mechanical, including photocopying, recording or by any information storage retrieval system,
w ithout permission from Pearson Education, lnc. GERMAN language edit ion published by
PEARSON EDUCATION DEUTSCHLAND, Copyright© 2010
Umwelthinweis: Dieses Buch wurde auf chlor- und säurefreiem PEFC-zertifiz ierten Papier gedruckt.
Um Rohstoffe zu sparen, haben w ir auf Fol ienverpackung verzichtet.
10 9 8 7 6 s 4 3 2 1
13 12 11 10
ISBN: 978-3-8273-2918-9
© 2010 by Addison-WesleyVerlag,
ein lmprint der Pearson Education Deutschland GmbH,
Martin-Kollar-Straße 10 - 12, D-81829 München/Germany
Alle Rechte vorbehalten Übersetzung: G&U Language & Publishing Services GmbH, Flensburg, www.GundU.com
Fach Iektorat: Phi lipp Homann, phil [email protected] Lektorat: Brig itte Bauer-Schiewek, [email protected]
Korrektorat Sandra Gottmann, Münster
Covergestaltung: Marco Lindenbeck, [email protected]
Herstellung: Phil ipp Burkart, [email protected] Satz: mediaService (www.media-service.tv)
Druck und Verarbeitung: Kösel Druck, Krugzell (www.KoeseiBuch.de)
Printed in Germany
Dieses Buch ist meiner wundervollen Frau Joan und unseren fünf Jungs gewidmet, die es ertragen haben, dass ich beim Schreiben dieses Buches ständig zu beschäftigt war.
Die Ewigkeit reicht nicht aus, um mit euch zusammen zu sein.
Inhaltsverzeichnis
ln haltsverzeichnis
Vorwort
Entwicklungswerkzeuge für Web-Apps
Der Aufbau dieses Buches
On Ii ne-Queiien
Voraussetzungen
Danksagungen
Der Autor
Kontakt mit dem Autor
1 Entwicklung mit Dashcode und Xcode
11
11
12
14
15
15
15
15
17
1.1 Dashcode und die benutzerdefinierte Vorlage Quick-ConnectiPhone 17
1.2 Xcode und die benutzerdefinierte QuickConnect-Vorlage verwenden 21
1.3 Erste Einführung in Objective-C 26
1.4 Die Struktur von QuickConnectiPhone-Anwendungen in Objective-C 29
1.5 Webinhalt einbetten: QuickConnectiPhone 33
1.6 Zusammenfassung
2 JavaScript-Modularität und iPhone-Anwendungen
2.1 Modularität
2.2 Das JavaScript-Framework von QuickConnectiPhone
ein Beispiel fü r Modularität
2.3 Die QuickConnectiPhone-Umsetzung des modularen Entwerfens
2.4 Implementierung von Unternehmens- und Ansichtsanwendungscontrol lern
2.5 Die Implementierung des Feh leranwendungscontrollers
2.6 Die Funktionalität der Anwendung erstellen
2.7 Zusammenfassung
41
41
43
53
Inhaltsverzeichnis
3 Benutzerschnittstellen f ür das iPhone erstellen
3.1 Die Schnittstellenrichtlinien von Apple
67
68
3.2 Listen- und browsergestützte Schnittstellen 71
3·3 Anwendungen mit nicht auf Listen beruhenden Ansichten 75
3·4 Immersionsanwendungen 8o
3·5 Benutzerdefinierte (55-Transformationen erstellen und verwenden 82
3.6 Ein Modul für Drag&Drop, Skalierung und Drehung erstellen und verwenden 90
3·7 Zusammenfassung 102
4 GPS, Beschleunigungsmessung und andere syst emeigene Funktionen von QuickConnect 103
4·1 Geräteaktivierung in JavaScript 104
4·2 Geräteaktivierung in Objective-C 111
4·3 Die Objective-C-Implementierung der QuickConnectiPhone-Architektur 120
4·4 Zusammenfassung 127
5 Google Maps einbetten 129
5·1 Abschnitt 1: Eine Karte in einer JavaScript-Anwendung mit
QuickConnect anzeigen 129
5·2 Abschnitt 2: Die Objective-C-Implementierung des Kartenmodu ls von QuickConnect 134
5·3 Zusammenfassung 147
6 Datenbankzugriff 149
6.1 Abschnitt 1: Die Beispielanwendung BrowserDBAccess 149
6.2 Abschnitt 2: SQLite-Datenbanken der WebKit-Engine verwenden 151
6.3 Abschnitt 3: Native SQLite-Datenbanken verwenden 157
6.4 Abschnitt 4: Das DataAccessObject in Datenbanken der WebKit-Engine verwenden 159
6.5 Abschnitt 5: DataAccessObject in nativen Datenbanken verwenden 172
8
Inhaltsverzeichnis
7 Datenzugriff über das Netzwerk
7.1 Abschnitt 1: Die Beispielanwendung BrowserAJAXAccess
7.2 Abschnitt 2: ServerAccessObject verwenden
7·3 Abschnitt 3: ServerAccessObject
7·4 Abschnitt 4: Sicherheitsfunktionen
7-5 Zusammenfassung
A Einführung in JSON
A.1 Abschnitt 1: Hintergrund
A.2 Abschnitt 2: Eine JSON-API für JavaScript
A.3 Zusammenfassung
B Evolution von QuickConnectFamily
8.1 Definitionen
Stichwortverzeichnis
187
188
190
196
208
209
211
211
213
216
217
219
221
9
Vorwort
ln diesem Buch lernen Sie, wie Sie eine neue Art von iPhone-Anwendungen erstellen:Web
Apps, die in einer Kombination aus HTML, CSS und JavaScript geschrieben sind. Dabei han
delt es sich um eigenständige Anwendungen, die wie normale iPhone-Programme direkt
auf dem Gerät ausgeführt werden, bei denen sich die Dateien aber nicht auf einem Server
im Internet befinden müssen.
Die erforderliche Entwicklungszeit und der Lernaufwand dafür, eine Anwendung in die
Hände Ihrer Kunden zu legen, ist bei Web-Apps geringer, da Sie weder Objective-C lernen
noch tiefe Kenntnisse des Frameworks Cocoa Touch haben müssen.
ENTWICKLUNGSWERKZEUGE FÜR WEB-ÄPPS
ln diesem Buch w ird das am häufigsten verwendete JavaScript-Softwarepaket aus dem
Open-Source-Bereich zum Schreiben von Anwendungen für das iPhone und den iPod
tauch behandelt, nämlich QuickConnectiPhone. Mit diesem Paket können Sie Anwendun
gen schreiben, die direkt in JavaScriptauf geräteeigene Funktionen zugreifen, z.B. Vibra
tion, GPS-Ortung, den Beschleunigungssensor usw. - und al l das, ohne eine einzige Zeile
Code in Obj ective-C oder Cocoa zu schreiben.
QuickConnectiPhone, das Sie von http:llsourceforge.netlprojectslquickconnect herunter
laden können, bietet den Zugriff auf die meisten geräteeigenen Funktionen und ein sorg
faltig entworfenes, vol lständig ausgestattetes Framework für die Entwicklung. Achten Sie
darauf, dass Sie QuickConnectFamily herunterladen. Zum Druckzeitpunkt dieses Buches
existiert dieses in der Version 1.5. Mit QuickConnect können Sie die Zeit bis zur Marktreife
Ihrer Anwendung verringern, da das Framework unter anderem den gesamten zusammen
hängenden Code enthält, den Sie gewöhnlich in Objective-C, Cocoa und JavaScript schrei
ben. Besonders schön ist, dass für die Nutzung der JavaScript-, HTML- und CSS-Dateien kein
Server im Netzwerk erforderlich ist.
Um den Lernaufwand zu verringern und das Verständnis zu verbessern, wurden überal l in
diesem Buch gute, sinnvol le Beispiele verwendet.
11
VOrwort
Wenn Sie installierbare iPhone-Anwendungen erstel len, die dazu erforderlichen Fäh ig
keiten erwerben und dynamische, ansprechende Lösungen schaffen wollen, die andere
Menschen gern benutzen, liegen Sie mit diesem Buch richtig, das Ihnen zeigt, wie Sie dieses
Paket verwenden.
Tabelle V.1 zeigt die einzelnen Funktionalitäten (zum Zeitpunkt der Abfassung dieses Buches).
Verfügbares Merkmal QuickConnectiPhone
GPS Ja
Beschleunigungsmesser Ja
Vibration Ja
Systemsounds Ja
Ad-hoc-Netzwerke (Bonjour) Ja
Netzwerke über Synchron isierungskabel Ja
Datenbankzugriff über Browser Ja
Integrierter Datenbankzugriff Ja
Drag&Drop-Bibliothek Ja
AJAX-Wrapper Ja
Aufzeichnung und Wiedergabe von Audiodateien Ja
Eingebettete Google-Karten Ja
Bibliothek f ür Diagramme und Grafiken Ja
Tabelle \1.1: QuickConnectiPhone-Funktionalitäten
DER AUFBAU DIESES BUCHES
Jedes Kapitel besteht aus zwei Teilen. Im ersten Teillernen Sie, wie Sie das betreffende Merk
mal von QuickConnectiPhone einsetzen, um eine bestimmte Aufgabe zu erledigen, z.B. um
die aktuellen GPS-Daten des Geräts abzurufen. Der zweite Teil zeigt Ihnen, wie der Code
hinter dem JavaScript-Auf ruf aussieht und wie er funktioniert. So können Sie selbst ent
scheiden, w ie t ief Sie in die JavaScript- und Obj ective-C-Hintergründe eintauchen wol len.
12
Vorwort
Das Buch ist w ie folgt aufgebaut:
> Kapitel 1, »Entwicklung mit Dashcode und Xcode«, zeigt Ihnen, wie Sie Dashcode
und Xcode mit QuickConnectiPhone einsetzen, um ansprechende Anwendungen
für das iPhone in kurzer Zeit zu erstellen. ln diesem Kapitelfinden Sie auch die
Grundlagen der Verwendung von Dashcode und Methoden zur Übertragung von
Dashcode-Anwendungen in Xcode, um sie kompi lieren und auf Geräten ausführen
zu können.
> Kapitel2, »Die Modularität von JavaScript für iPhone-Anwendungen«, beschreibt, wie
Sie die Zeit bis zur Marktreife bedeutend verringern können, indem Sie die Modula
rität des Framewerks QuickConnectiPhone nutzen. Hier erfahren Sie auch, wie Sie
Frontcontroller, Anwendungscontroller und die Ei nbi ndu ng von JavaScript rea Iisieren.
> Kapitel 3, »Benutzerschnittstellen für das iPhone erstellen«, hilft Ihnen dabei, Ihre
Anwendungen so zu schreiben, dass sie den Verteilungsrichtlinien für den Apple
App Store genügen. Hier lernen Sie die empfohlenen Vergehensweisen zum Erstel
len nützlicher iPhone-Anwendungen kennen. Es werden ebenso die verschiedenen
Arten von Anwendungen beschrieben, die gewöhnlich für das iPhone geschrieben
werden, als auch die Fallstricke, derer Sie sich bewusst sein müssen.
> Kapitel 4, »GPS, Beschleunigungsmessung und andere systemeigene Funktionen
von QuickConnect«, zeigt Ihnen, wie Sie GPS-Daten, Beschleunigungsmesswerte
und Gerätebeschreibungen abrufen, wie Sie das iPhone vibrieren lassen und wie
Sie Audiodateien abspielen und aufnehmen. Hier greifen Sie mit dem Framework
QuickConnectiPhone auf diese geräteeigenen Merkmale zu und nutzen sie. Damit
wirken Ihre Anwendungen wirklich wie für das iPhone gemacht, und der Komfort
ihrer Anwendung erhöht sich.
> ln Kapitel 5, »Google Maps einbetten«, erfahren Sie, wie Sie mit QuickConnect
iPhone eine Google-Karte in Ihre Anwendung aufnehmen. Dies ist eines der am
stärksten nachgefragten Merkmale. Dadurch müssen Sie Ihre Benutzer nicht län
ger auf die Anwendung Karten verweisen.
> Kapitel6, »Datenbankzugriff«, zeigt, wie Sie Informationen aus Datenbanken abru
fen und darin speichern, um diese dann in Ihrer Anwendung zu nutzen. Die Daten
banken erstellen Sie mit dem Framework QuickConnectiPhone. Müssen Sie zusam
men mit Ihrer Anwendung eine vordefinierte Menge von Daten in einer Datenbank
ausliefern? Dann lesen Sie dieses Kapitel!
13
VOrwort
> ln Kapitel 7, »Datenzugriff über das Netzwerk«, geht es darum, wie Sie in Ihrer in
sta llierten Anwendung auf Daten von Servern oder Diensten im Netzwerk zugreifen
und sie verwenden. Dies geht sehr einfach mit einem Wrapper, der Sie die Informa
tionen von einem anderen Ort abrufen lässt. Wenn Sie z.B. Daten von einem Online
Biog beziehen und mit einem Twitter-Feed zusammenführen müssen, erleichtert
das QuickConnectiPhone-Modul für den Datenzugriff über das Netzwerk diese
Aufgabe.
Darüber hinaus gibt es noch folgende Anhänge:
> Anhang A, »Einführung in JSON«, gibt eine ku rze Einführung in JSON (JavaScript
Object Notation). JSON ist eine der am häufigsten verwendeten und einfachsten
Möglichkeiten, um Daten überall dorthin zu übertragen, wo sie gebraucht werden.
> Anhang B, »Evolution von QuickConnectFamily«, gibt einen Überblick über die künf
tige Entwicklung von QuickConnectiPhone. Wenn Sie Anwendungen für iPhones
und andere Plattformen erstellen möchten, z.B. für die Android-Telefone von Google,
Nokia- oder Blackberry-Handys oder Desktopsysteme mit Mac OS X, Linux oder Win
dows, sollten Sie einen Blick in diesen Anhang werfen.
ÜNLINE-QUELLEN
QuickConnectiPhone unterliegt einer raschen Entwicklung. Um auf dem neuest enStand
der j üngsten Funktionen und Fähigkeit en zu bleiben und um mehr zu lernen, nutzen Sie
die folgenden Links.
QuickConnectiPhone
> Beispiele und das Framewerk können Sie von https://sourceforge.netlprojectsl quickconnect/ herunterladen.
> Einen Blag zur Entwicklung mit QuickConnect finden Sie auf http:lltetontech. wordpress.com.
> Das Wiki befindet sich auf http:llquickconnect.pbwiki.com/FrontPage.
> Die Google-Gruppe finden Sie auf http:llgroups.google.comlgroupl quickconnectiPhone/.
> Twitter-Meldungen gibt es auf http:lltwitter.comlquickconnect.
14
Vorwort
VORAUSSETZUNGEN
Um Nutzen aus diesem Buch ziehen zu können, brauchen Sie Grundkenntnisse in HTML,
CSS und JavaScript. Wenn Sie damit bereits Webseiten erstellt haben, sind Sie schon gut
für die Entwicklung von iPhone-Anwendungen vorbereitet. Wo in Qu ickConnectiPhone
Hilfestellung zum Objective-C-Code erforderl ich ist, wi rd sie auch gegeben. Dieses Buch
ist aber keine Einführung in Objective-C und keine An leitung dazu, wie Sie iPhone-Anwen
dungen in Objective-C schreiben.
Sie müssen die Xcode-Werkzeuge von Apple von der iPhone-Entwicklerwebsite unter
http:!!developer.apple.comliphone herunterladen. Dazu brauchen Sie Mac OS X 10.5 oder
höher und einen Mac mit lntei-Chipsatz.
Es ist zwar nicht erforderlich, dass Sie über ein iPhone oder einen iPod touch verfügen,
doch ist dies sinnvol l, um die Anwendungen auf diesen Geräten testen und ausführen zu
können.
DANKSAGUNGEN
Mein besonderer Dank gilt Daniel Barney, der den Code für eingebettete Google-Karten
durchgearbeitet und korrigiert hat. Außerdem möchte ich meinen Mitarbeitern im Com
puter Information Technology Department der Brigham Young University in ldaho für das
Zuhören und ihre Anregungen danken.
DER AUTOR
LeeS. Barney (aus Rexburg in ldaho) ist Professor im Computer Information Technology De
partment des Business and Communication College an der Brigham Young University ldaho.
Er war als CIO und CTO von @HomeSoftware beschäftigt, einem Unternehmen zur Herstel
lung webbasierter, mobiler Daten- und Zeitplananwendungen fü r die private Gesundheits
vorsorge. Davor hat er über sieben Jahre lang als Programmierer, leitender Software-Ingeni
eur, Qualitäts-, Entwicklungs- und Projektmanager für AutoSimulations lnc. gearbeitet, den
fü hrenden Hersteller von Planungs- und Terminsoftware für die Halbleiterindustrie. Er ist
der Autor des Buches Oracle Database AJAX & PHP Web Application Development.
KONTAKT MIT DEM AUTOR
Per E-Mail erreichen Sie den Autor (in englischer Sprache) über [email protected].
Für andere Formen der Kontaktaufnahme nutzen Sie die weiter vorn angegebenen Twitter-,
Wiki- und Google Groups-Links.
15
Entwicklung mit Dashcode und Xcode
Wenn Dashcode und Xcode zusammen eingesetzt werden, bieten sie die Leistungsfähig
keit und einfache Verwendbarkeit, die Sie benötigen, um einmalige, spannende und hybri
de iPhone-Anwendungen zu schreiben. Da beide Tools um benutzerdefinierte Vorlagen f ür
iPhone-Web-Apps erweitert wurden, brauchen Sie keinen eigenen Objective-C-Wrapper zu »backen«. in den ersten beiden Abschnitten erfahren Sie, wie Sie vorhandene Vorlagen
f ür iPhone-Web-Apps f ür Dashcode und Xcode verwenden, mit denen Sie recht schnell
zum Ziel kommen. Außerdem finden Sie in den Abschnitten 3 bis 5 eine ku rze Erörterung
der Grundlagen von Objective-C und darüber, wie eine in dieser Sprache geschriebene
iPhone-Anwendung in dem am meisten genutzten Framework für Web-Apps- QuickConnectiPhone- struktu riert ist.
1.1 DASHCODE UND DIE BENUTZERDEFINIERTE VORLAGE
QU ICK-(ON N ECTI PHON E
Da ein großer Tei l der Benutzeroberfläche und der Interakt ion f ür iPhone-Web-Apps mit
HTML, JavaScript und CSS erstellt wird, erfolgen Entwicklung und Fehlerbehebung über
wiegend in Dashcode. Der mit Drag&Drop ausgestattete Oberflächengenerator ist in sei
nem Umfang und der Leichtigkeit seiner Anwendung einmalig. Um die Anwendung zu
Kapitell Entwicklung mit Dashcode und Xcode
erstellen, wird überwiegend Dashcode eingesetzt . Außerdem erledigen Sie mithilfe des zu
gehörigen Simulators und der integrierten Debugging-Tools auch die Fehlerbehebung.
Da der größte Teil des Codes für iPhone-Hybridanwendungen ähnlich aussieht, macht das
Erstellen einer ent sprechenden Vorlage das Neuschreiben oder Importieren des gemeinsa
men Codes zu Beginn jedes neuen Projekts überflüssig. Eine Abhandlung zum gemeinsamen
Code finden Sie in Kapitel2, »Die Modularität von Objeetive-C und iPhone-Anwendungen«.
Sie können QuickConnect von folgender Adresse herunterladen: http://sourceforge.net/ projectslquickconnect.ln diesem Download ist eine Dashcode-Vorlage enthalten, die Ihnen
beim Erstellen von iPhone-Hybridanwendungen hi lft. Die Installationsroutine für Quick
ConnectFamily fügt diese Vorlage in Dashcode ein.
r KEINE QUICK(ONNECTIPHONE-VORLAGEN FÜR DASHCODE 3.0
Zum Druckzeitpunkt dieses Buches liegt QuickConnect in der Version 1.5 vor. Diese Ver
sion unterstützt derzeit noch keine Vorlagen für die m it Snow Leopard erschienene
Dashcode Version 3.0. Möchten Sie dennoch die Vorlagen nutzen, installieren Sie bitte
das Xcode SDK für Leopard, dieses beinha ltet Dashcode 2.0.
C Dashcodt Abl.a9t l!eatb~itEn F~rmat Anordnen Ol?bug Darstellung Ftnntr Hilft
@ "' !""'! Ul'lbol'!.a.ntn
8 1ntroZ
~j)'t09f~mm:.t1ributt
m·"'""
8C ... 'e<gi)I"ISi~ O'*fiO Uil 4U lli ~IIO~IIek. l"' CEfl Mtlt•tstXY"~ ICl t.llcll!IUcm Si:<llc OvmKil ' ' ' u -d« O~jc:k!c io'l d c.n i ,.II)M."i OCitoc!l, 3 Artu:lu~cidl
lrlt(lf'i'nl!IOIIt ll
>
W Al~ ertt<i~: ruJl.iertn -
Hol!ldler & COde hin • C!!l!:m!a ~ Attribu t~ fc:s d ett:n
I ti I. • • ' iil( \ 4 ; ' I!<Stl; ' IJXI'
0 UD ~ ' · i•td ' ' ' I.;,'? ' ' ' h~' ' ' ' ' ' ' i&S5 •
Q~~ntCOnll ••
MII ~itH A~h'< IU!Sl'lrti!)! ._.if!J Ot rt 8:Hii112l'f ~r(lue~;. c&.:IH getldt" Wie l!l'ar~ ltunv )W,!t lh:IC:t,
~ Abbildung 1.1: Die Vorlage QuickConnectiPhone wird in Dashcode verwendet.
Sie sehen das Standarddialogfeld Bibliothek.
18
Dashcode und die benutzerdefinierte Vorlage Quick-ConnectiPhone
Nachdem Sie die Installationsroutine für QuickConnectFami ly ausgef ührt und Dashcode
gestartet haben (Dashcode befindet sich auf Ihrer Festplatte unter /Developer/Applica
tions), finden Sie unterhalb der Dashcode-Widgets die Vorlage Qui ckConnect i Phone am
Ende des Dialogfelds zur Auswahl. Ein Doppelklick auf das Symbol Qui ckConnec t i Phone
bringt Sie direkt zum Dashcode-Hauptbildschirm, in dem die leere Benutzeroberfläche an
gezeigt wird. Abbi ldung 1.1 zeigt, wie die Dashcode-Anwendung in Betrieb aussieht.
Um die im Framewerk integrierten Dateien zu verstehen und problemlos anwenden zu können, müssen Sie zunächst mit Dashcode eine einfache Benutzeroberfläche erstel len
und sie Ihrem iPhone mit Xcode bereitstellen. Die Oberfläche, die hier erstellt w ird, besteht
led iglich aus einer Schaltfläche und einem Textfeld. Wird die Schaltfläche betätigt, zeigt
das Textfeld »Welcome«.
WEB-ÄPPS UND DAS DIALOGFELD ALERT
Wer häufig in Objective-C schreibt, benutzt oft das Dialogfeld ALERT, um Fehler in einer
Anwendung zu suchen oder dem Benutzer etwas mitzuteilen. Die Objective-C-Funk
tion al ert ist eigentlich nichts, was vom Objective-C-Modul erledigt wird, sondern ein
Aufruf in den nativen Code des umschließenden Browsers.
Dies ist in QuickConnectiPhone-Anwendungen nicht integriert, wei l die Verwendung
von Dialogfeldern die von Apple festgelegten Standards für die iPhone-Benutzerober
fläche verletzt. Für die Fehlerbehebung bietet sich der Dashcode-Debugger an. Stellen
Sie Ihre Anwendung auf Xcode um, können Sie mithilfe der Funktion debug Meldun
gen in der Xcode-Konsole ausgeben.
Um Benutzern wichtige Informationen zu übermitteln, fügen Sie sie unabhängig vom
verwendeten Tool in ein di v- oder ein anderes HTMl-Eiement ein.
Um diese Benutzeroberfläche zu erstellen, überzeugen Sie sich zunächst, dass das Dialog
feld BIBLIOTHEK geöffnet ist. Wenn nicht, klicken Sie auf das entsprechende Symbol in der
obersten Leiste von Dashcode. Suchen Sie anschließend das Element TEXT am Ende der
Elementbibliothek, und ziehen Sie es auf den leeren Anwendungsbi ldschirm. Dann wird
oben in der Oberfläche Ihrer Anwendung ein Textbereich angezeigt, der das Wort Te xt
enthält. DieserText weist standardmäßig eine Breite von 100 Prozent auf Dashcode stellt
in der Ihrer Anwendung zugrunde liegenden Datei i ndex . html ein HTML-di v-Tag sowie
etwas Objective-C-Code bereit, um den Bereich nach Belieben mitText, Hintergrundfarben
usw. zu füllen .
19
Kapitell Entwicklung mit Dashcode und Xcode
Für dieses Beispiel setzen Sie die ID dieses di v-Tags auf di spl ay und leeren das Text
feld. Dazu verwenden Sie den Entitäteninspektor der Oberfläche, indem Sie das Dialogfeld
durch Auswahl des Informationssymbols in der obersten Symbol leiste von Dashcode akti
vieren. Wechseln Sie auf die rot-weiße Registerkarte in der linken oberen Ecke des Informa
tionsdia Ioges, setzen Sie das ID-Feld auf di spl ay und leeren Sie das Feld BEZEICHNUNG.
Versehen Sie die Oberfläche nun mit einer PusH-Schaltfläche, indem Sie sie hineinziehen
und außerhalb des Textfelds ablegen. Der Informationsdialog zeigt jetzt anstel le der In
format ionen für das Textfeld diejenigen für die Schaltfläche an. Markieren Sie den blauen
Kubus in der rechten oberen Ecke des Dialogfelds INFORMATIONEN, um die Registerkarte
BEHAVIORS zu öffnen. Dort können Sie Objective-C-Funktionen als Handler für alle Ereig
nisarten definieren, die in der Benutzeroberfläche vorkommen. Beachten Sie, dass zahl
reiche übliche Obj ective-C-Mausereignisse fehlen . Sie wurden durch ongesturestart, ongesturechange und engestureend ersetzt. Geben Sie im Handler-Abschnitt des
Ereignisses onc l i ck changeText ein. Damit wird eine FunktionchangeText in die Datei
ma in. j s eingefügt und angezeigt. Sie können nun definieren, was geschieht , wenn das
Ereignis onc l i ck ausgelöst wird. ln diesem einfachen Fall f ügen Sie folgenden simplen Code in die FunktionchangeText ein:
document.getEl ementßy l d( 'displ ay ' ).innerHTML = ' We l come ' ;
Damit ist die Beispielanwendung so weit, dass sie im iPhone-Simulator ausgeführt wer
den kann. Mit dem Symbol AusFÜHREN in der linken oberen Ecke von Dashcode starten
Sie den Simulator und führen Ihre Anwendung darin aus. Abbildung 1.2 zeigt die Beispiel
anwendung im Simulator.
20
~ Abbildung 1.2: Die einfache Beispielanwendung wird nach einem Klick auf die Schaltjläche im Dashcode-Simulator ausgeführt.
X-code und die benutzerdefinierte QuitkConnect-Vorlage verwenden
Nachdem Sie mit der Erstellung und Fehlerbehebung der Anwendung fertig sind, können
Sie dazu übergehen, den Code zur Bereitstellung als installierbare Anwendung in Xcode
umzuwandeln. Zunächst verwenden Sie Dashcode dazu, die betreffende Anwendung
bereitzustellen. Wenn Sie darauf verzichten, bleibt der Code in Ihrem Dashcode-Projekt
verborgen. Er enthält Direktiven, die nur Dashcode versteht.
Klicken Sie auf das Symbol BEREITSTELLEN links auf dem Dashcode-Bildschirm, um den
Bereitstellungsdialog einzublenden.Jetzt können Sie den fertigen HTML-, CSS- und Objective
C-Code in einer Form auf der Festplatte speichern, die sich in Ihre Anwendung einbetten lässt.
Geben Sie im Feld PFAD einen Namen f ür ein neues Verzeichnis ein, um es auf der Festplatte
Ihres Rechners anzulegen. Dort werden die Dateien anschließend gespeichert. Sie sind jetzt
auch für den Import in Xcode bereit.ln Abbi ldung 1.3 sehen Sie den Bereitstellungsdialog.
Weitere Informationen darüber, welche Obj ective-C-Dateien in dieser Vorlage enthalten sind und w ie sie die Erstellung von Anwendungen erleichtern, finden Sie in Kapitel 2.
1.2 XCODE UND DIE BENUTZERDEFINIERTE QUICK(ONNECT
VORLAGE VERWENDEN
Da Sie die Installationsrout ine Oui ckC onnectFami l y ausgeführt haben, ist die Xcode
QuickConnectiPhone-Vorlage App l i ca t i on instal liert, mit der Sie j etzt das Xcode-Pro
jekt fü r Ihre QuickConnectiPhone-Hybridanwendung erstellen. Dieser Abschnitt führt
Sie durch den Vorgang. Das Wiki Oui ckConnectFami l y enthä lt ein Video dazu (http:! I quickconnect.pbwiki.com!Moving-Dashcode-projects-to-Xcode) .
Als Erstes wählen Sie NEW_ PROJECT. Mit SELECT IPHONE OS APPLICATION S wi rd das Symbol
Q UI CK( ONNECT IPHONE ÄPPLICATION angezeigt. Doppelklicken Sie darauf, benennen Sie Ihr
Projekts i mp l eExamp l e und wählen Sie ein Verzeichnis, in dem Sie es auf Ihrer Festplatte
unterbringen wol len, oder legen Sie eines dafür an. Xcode erstellt dann ein Projekt, das die
Obj ective-C-Dateien enthält, die erforderlich sind, um Ihre Objective-C-Anwendung direkt
ohne Netzwerk- oder Internetzugriff auf dem Gerät auszuführen. ln der Gruppe RESOU R
CES Ihrer Anwendung finden Sie einige HTML-, CSS- und Objective-C-Piatzha lterdateien.
Eine dieser Platzhalterdateien ist i ndex. html . Sie ent hält den HTM L-, CSS- und Objective
C-Code für eine ausführungsbereite Beispielanwendung. ln Abbildung 1-4 sehen Sie, wie
sie als insta llierte Anwendung im Simulator ausgeführt wi rd.
21
Kapite l l Entwicklung mit Dashcode und Xcode
ti Dashcode Abl.lge Bearbeiten Format Anordnen Debug Darstellung Fenster Hilfe
B tnuo2
ebwnon '2S' di~pl:.y
:~· PloQtamru.trtlbut~ :::.·.·.· ..... ~ Webc!ip-S.,."bol
I ~ . .
Otteien
js fur.ct.on!>.JS
U tmo1gcs !f. inde:x.html
.i! mappil'lg$.jS
CJ mobile
..::J irn.lges cu mo1in.cn
...,J P.uts
c:J Parh (:j QCi ••• .,.
0 · ·- 0 E::
I I
simple:Examole (Arbeitet)
inuo2 fü r Webs e.rver bQ:reltstcallen
.~1'"", _IR_~_ Zl.iltUt r;ICII'f'C)l 'I
0
Zielort ' c;;loc. lh..t ~
(!1 Slmul:thOrt cer AIJsfi:l'ltung in OO.'I"'l in : M .to n tol't.ICXJI
Opeionfl:n
Verh:.llen beim Sichern ProJakt -o c:am tk~•Uti::litft~ut ::JE Hto·.-.ne #~trn
komprlmiervng ~ J~v.JScnpt fUr schnelleren 00Wfllo.ld komprirnie rM
Ben.adtri(hllgung C E- M3II mlt Unk 2üM bereltgene!lttl\ Wtbprogt:.'llnlu'WI senden
( Auf der Fe>tplatte sichern ... ) (~ _ ____;B:..:•:..:re"'its"'te:..:lle:c:• __ _,.
~ Abbildung 1-3: Der Bereitstellungsbildschirm zeigt die Bereitstellung der fertigen Anwendung im Verzeichnis ChaptenExample auf dem Webserver.
Um die zuvor in Dashcode erstellten Dateien in diesem Projekt einzufügen, löschen Sie die
folgenden Dateien:
> i ndex.html
> ma in . css
> mai n . j s
> Dateien in der Gruppe PARTS
> Dateien in der Gruppe IMAGES
Anschließend importieren Sie die Dateien index. html , ma in . css und ma in . js. Dazu
klicken Sie bei gedrückter ~-Taste mitderrechten Maustaste aufdie Gruppe RESOURCES
und wählen Aoo_EXISTING FILES. Wechseln Sie in das Verzeichnis, in dem Sie Ihre Dashcode
Anwendung bereitgestellt haben, und markieren Sie die Dateien i ndex . html , ma i n. css
22
X-code und die benutzerdefinierte Quit kConnect-Vorlage verwenden
und ma i n . j s. Sie können sie in das Xcode-Projekt kopieren oder dort benutzen, wo sie
liegen. Aktivieren Sie f ür dieses Beispiel bei jeder Aufforderung das Kontrollkästchen CoPv
ITEMS INTO DESTINATION GROUP'S FOLDER.
~ Abbildung 1.4: Die QuickConnect-Standardanwendung
KOPI EREN ODER NICHT KOPI EREN - DAS IST H IER DIE FRAGE
Ob Sie die vorliegenden Dateien kopieren oder Xcode mit Referenzen darauf arbeiten
lassen, ist Ihre Sache. Wie entscheiden Sie sich? Beide Methoden haben ihre Vorteile.
Kopieren Sie die Dateien, ist das Projektverzeichnis vollständig und kann anderen Ent
wicklern übergeben werden, ohne dass diese die Verzeichnisstruktur des Rechners
replizieren müssen, auf dem die Originale liegen.
Bei Verwendung von Referenzen können Sie zu Dashcode zurückkehren, um Änderun
gen vorzunehmen, und das Projekt anschließend exportieren, um die Dateien zu über-
~hreiben. Sie brauchen sie nicht erneut in Xcode zu importieren.
Als Nächstes klicken Sie mit der rechten Maustaste auf die Gruppe PARTS und import ieren
die Dateien in den gleichnamigen Ordner. Sollte die Gruppe PARTS nicht vorhanden sein,
legen Sie diese an. Wiederholen Sie diesen Schritt f ür die Gruppe IMAGES. Nun sind Sie fast
so weit, dass Sie die Anw endung ausf ühren können.
Da Dateien in die Gruppe RESOURCES aufgenommen w urden, muss Xcode angewiesen
w erden, sie in die von der Anwendung verwendet en Ressourcen einzubinden. Erweitern
Sie die Zielauswahl (TARGETS) am unteren Bildschirmrand sowie Ihre Anwendung und das
23
Kapitell Entwicklung mit Dashcode und Xcode
Listing COPY BuNDLE RESOURCES. Sie sehen jetzt die Ressourcendat eien, die Ihre Anwen
dung braucht, um zu laufen. Markieren Sie die Dat eien (nicht die Gruppen), die Sie gerade
in Ihr Projekt aufgenommen haben, und ziehen Sie sie in das genannte Listing. Erweit ern
Sie ansch ließend die Liste CoMPILE SouRCES, und löschen Sie alle Objective-C-Dateien. Sie
werden offensicht lich nicht kompil iert. Klicken Sie dazu bei gedrückter ~-Taste mit
der rechten Maustaste darauf, und wählen Sie DELETE. Damit entfernen Sie sie aus der
Kompilierungsl iste, aber nicht aus dem Proj ekt oder von der Festplatte.
Da Dashcode Verzeichn isse verwendet, Xcode j edoch Gruppen, müssen Sie zwei weitere
Änderungen vornehmen, um Ihre Anwendung starten zu können. Die erste erfolgt im Ab
schnitt <head> der Datei i ndex . ht ml . Da die Objective-C- und alle übrigen referenziert en
Dateien im Ressourcenverzeichnis derfertigen Anwendung liegen, müssen die Verzeichnis
verweise auf Pa rts und OCiPhone entfernt werden. Vorher sieht ein <scr ipt>-Tag
beispielsweise folgendermaßen aus:
<scri pt t ype= "text / javascript " sr c="Parts /u t i l iti es.js" charset= "ut f - B" ><I script >
Hinterher sollte es aussehen wie folgt :
<scri pt t ype= "text / javascript " sr c="ut i l i t i es. j s" charset="utf - 8" > <l scr ipt >
tl Xcod• File Edlt View P!Oje<t Bulld RI.An Design SCM \Vindow f He!p Quld<.Connt ct t S.t 8:32 PM 0. 0 r n n R 0 0 ;~ Pu.n&uaon:., Slmpl..._,..le - ...o;.ct F;nd
Actio.oe:TUSII!t
~<M~,·~··~•g••~~=~ll· lt.~ p{'Go:. I .,. ~!!:;~~:::c:lc • 0 Display lluults ln F.ncl Sm31't Cro11p
~ 5 "nd t(louna!CIIIpg0 ., )'} P"'":~~:~Q'tl'lttlx • 'lm• u r -t Stl1t Eiemrnt.!d ,
f!] l lnP!oittt
t!.l I'"""" I Ccl!.tiWIIS
~ Sl-npifb~·~ppO .- ~ D~s~codc to Xcodt.blt
~ ==~=:~:~: U StJ.I(h 1t-.roUQn tne Pvs~6Unor.Js f'llt fc.r "11'!1iGur Ir\ l l)ti llon y;r!tt;JS
... Q OIIIH SOJrces •OA.e~o:.~rces
• CJi m;)QI!S
1:1 b~l'lll)!l_(ll(kfc:l,, ~ i:tDvMin.pn~
·o~~ ii s.ttuOJS fs' Tr.:M itioM .j:. {~ T!<'lfiS!.,O,S.C:n jfTu\Js
: I c:::J!L) IJ }·~~
' ; j g lgnorcc.ue ( <>pttons ... }~
),!. St,)~.C:UlO Ut$ ~~ l'utfiBIItlOf'l~ $ ~ lonmni-Urld!~r.J ~ l i llli.h iu h ~ ~~(f'II~I!. IXt -, ,.
llnlkd UMI ,. • li"!.uJ~~w.~~~~~=~r..h::----------=-''-'.• .:::l~illTC~· ~··~ot~ ~::~;~ ~~ ~:::::~~~:~=~~~h~:~~~::~~~:~~~~ ~~;8 ; r! ~ Mli~Vi"d::~W.lllb lO thls..topi iUI~tdtll • (I; t ij) dct•bucOd hliticfl.j) ~ tll !1t -bcltto• l~111tll · 0 ; t.--.... HI.I'I • • u tlla._QOII~o i~t .. e1 ~
fu l n(o.pllu &I II e~~ntll'> lFL oi W:Hjt'OII1!1 IOO:f"S
.,EJQCI~45
~ tlll~ •• oontoln.etn1gM • • e~ l .t) OUilCCOeiOX<Od e.O 6S t h! :S.ßUUd: ta!se;
•Cifr~·~' 0 ~:!s~j~~:~ :~::;;9; 1~'-! '~;~t. , td; .. tiiJcorteraon o.tr•Mt11 ~ tll! :~ .~n~:nelltltl ltw;J~~I'il1. = t ll ~IICf't~rtr .. ·.cH~~.rn.:l' ; •~UI<it. lrumcwotk 69 •CJ tt c~dCI!i ;o II tr""''~ "'"'ll'r.ll "~•s
.. 9roui'IC:)t $0fl.ffltl!f WOI 1l 1'61 rtyl t ;
•CJao~:~tbunp!c:.~~P " ~ .. r t h!t.J:ac:t , rOU'di tiHIO:'It- d~eu'JIQ'.t.er:.oto:.::t_.._t<•ow'>·
ts::o..lld ·~tur · l o«vrr<e~<M fourcl ·n•our - ! « OJrrl!r<ts
~ Abbildung 1-5: Der Suchbildschirm zeigt die Ergebnisse der Suche nach Images I im gesamten Projekt.
24
X-code und die benutzerdefinierte QuitkConnect-Vorlage verwenden
Da für alle in Dashcode erstellen Scha ltflächen usw. Bilder benutzt werden, müssen Sie
außerdem al le Instanzen des Strings I mages / im Projekt suchen und durch leereStrings
ersetzen. Dazu gehen Sie einfach ins Menü EDIT, wählen FIND _FIND IN PROJECT und suchen
dann I mages/. Abbildung 1.51istet die Suchergebnisse für dieses Beispiel vor dem Ändern
der Datei Pus hßu t t on. j s auf.
Nun können Sie Ihre Anwendung mithilfe des Symbols BUILD AND Go installieren und ausführen, das Sie in der obersten Symbolleiste von Xcode finden. Wi rd der Feh ler »No
provisioned iPhone OS device is connected« gemeldet, können Sie die Anwendung an statt
auf Ihrem Gerät im Simulator insta llieren und ausführen. Klicken Sie auf SucCEEDED in
der rechten unteren Ecke des Xcode-Fensters, wäh len Sie die Liste DEVICE I DEBUG in der
linken oberen Ecke des Dia logfelds, das eingeblendet wird, und klicken Sie auf die Auswahl
SIMULATOR. Beachten Sie, dass Sieweiter unten in der Liste auch RELEASE oR DEBUG wäh len
können. Dieses Dialogfeld sol lten Sie im Lauf der Entwicklung häufig einsetzen, um Ände
rungen der beschriebenen Art durchzuführen. in Abbi ldung 1.6 sehen Sie die installierte
Anwendung bei der Ausführung im Simulator.
~ Abbildung 1.6: Die Anwendung simpleExample wurde im Simulator installiert und wird dort ausgeführt.
Herzlichen Glückwunsch- Sie haben gerade Ihre erste iPhone-Hybridanwendung fertig
gestel lt.
25
Kapite l l Entwicklung mit Dashcode und Xcode
r PROVISION ING ? WAS IST DAS?
Provisioning ist der aus mehreren Schritten bestehende Vorgang, den Sie oder jemand,
der Sie darstellt, durchführen muss, damit Sie Ihre Anwendung auf einem Gerät instal
lieren und ausführen können.
Um Ihr iPhone entsprechend nutzen zu können, müssen Sie Mitglied der Apple Deve
loper Connection (ADC) sein und sich fü r die Benutzung des Program Porta l registriert
haben. Sind Sie Teil eines Teams, ist das Provisioning möglicherweise bereits erledigt; in
diesem Fall brauchen Sie nur noch die betreffenden Daten auf Ihr iPhone hochzuladen.
Umfangreiche Informationen zum Provisioning finden Sie in der ADC. Achten Sie da
rauf, alle aufgeführten Schritte durchzuführen. Jede Abweichung kann zum Fehlschlag
füh ren, was Sie daran hindert, Ihre Anwendungen auf Ihrem Gerät zu testen. _j
1.3 ERSTE EINFÜHRUNG IN ÜBJECTIVE-(
Dieser Abschnitt stellt weder ein umfassendes Objective-C-Tutorium noch eine ausführliche
Erörterung der Verwendung von Objective-C zum Schreiben von iPhone-Anwendungen
dar, sondern vermittelt Ihnen eine Vorstellung davon, wie die in den Vorlagen benutzten
Obj ect ive-C-Kiassen interagieren und sich verhalten, sodass Sie dieses Wissen in iPhone
Hybridanwendungen nutzen können. Es wird Grundwissen über Objekt e, Methoden und
Attribut e vorausgeset zt. Wollen Sie mehr über das JavaScript-Framework wissen oder nicht s
überObjective-C-Code erfahren, können Sie den Rest dieses Kapit els überspringen und direkt
zu Kapit el 2 gehen. Einen tieferen Einblick in die iPhone-Entwicklung in Objective-C bietet
Das iPhone-Entwicklerbuch: Rezept e für Anwendungsprogrammierung mit dem iPhone
SDK von Erica Sadun.
Objective-C ist eine interessant e Sprache. Für Leser mit Kenntnissen in JavaScript, PHP,Java,
Perl oder anderen Sprachen kann sie zunächst abschreckend und unbegreiflich wi rken.
Trot zdem verdient sie einen zweiten Blick, und zwar nicht nur, weil es sich um die »native«
Sprache des iPhone handelt.
Objective-C ist eine objektorientierte Va riant e von C. Sie können damit die gesamt e leis
tungsfahige, spannende Programmierung in der Art von C/C++ durchführen, beispielsweise
Zeigerarithmetik, sowie ein iges, was Ihr Leben vereinfacht, beispielsweise automatische Spei
cherverwaltung. Zu den ersten Dingen, die Sie in einer objektorientierten Sprache erledigen
müssen, gehört das lnstanzi ieren eines Objekts. Steht im Obj ective-C-Quellcode ein Objekt
mitdem Namen Wirbeltiermitden beiden Attribut en nameund anza h7 BeinezurVer
fügung, w ird es wie folgt inst anziiert:
var einWirbel t ie r = new Wirbel t i er ("Laubfrosch" , 4) ;
26
Erste Einführung in Objective-C
Mögl icherweise halt en Sie dies f ür normal und erwart en, dass sich andere Sprachen ge
nauso verhalten.
Die lnstanzi ierung in Obj ective-C sieht zunächst merkwürdig aus, wenn Sie diese Erwar
tung hegen:
Wirbel t i er *ei nWi rbel tier = [[Wirbeltier al l oc] i nitWithName: @"Laubfrosch" andAn zahl ßei ne : 4];
Einige Teile erscheinen verständl ich, andere nicht. Wenn Sie darüber nachdenken, ergibt
a 7 7 oc Sinn, weil es beschreibt, wie dem Obj ekt Wi rbe 7 t i er Platz im RAM zugewie
sen wird. Sogar i n itWi thName und andAnz ah7 Bei ne ergeben Sinn, wei l sie die beiden
benötigten Parameter setzen bzw. übergeben. Aber was geschieht eigentlich und was
bedeuten die eckigen Klammern?
Obj ective-C benutzt für alle Interaktionen mit Objekten und anderen Elementen, die in
anderen Sprachen im Unterschied zu Obj ective-C möglicherweise keine Obj ekte sind,
Meldungsübergabe (Nachrichten). Betrachten Sie die folgende Codezeile:
[W i rbel tier al l oc]
Es wurde bereits erwähnt, dass in diesem Codefragment einem Objekt mit dem Typ
Wi rbe 7 tierPlatz im RAM zugewiesen wird. Die eckigen Klammern um Wi rbe 7 tierund
a 7 7 oc geben an, dass das Obj ekt in der Anwendung, das f ür die Klasse Wi rbe 7 t i er steht,
die Meldung a 7 7 oc erha lten soll. Das Codef ragment ist folgendermaßen zu lesen: »Übergib dem Objekt der Klasse Wi rbe 7 tiereine al/oc-Me/dung.« Das Ergebnis der Übergabe
dieser a 7 7 oc-Meldung an das Obj ekt der Klasse Wi rbe 7 ti er ist, dass ein Zeiger auf ein
neues Wi rbe 7 ti er-Objekt zurückgegeben wird.
r ZE IG ER? WAS IST DAS?
Zeiger sind interessant. Viele haben Angst davor, weil sie sie nicht verstehen oder nicht
wissen, worum es sich handelt.
Um sie zu verstehen, hier eine Ana logie: Stellen Sie sich eine große Menschenmenge
vor, darunter Alma und John. Sie kennen sich, und Alma weiß, wo sich John in der Men
ge befindet. Sie nähern sich Alma und fragen sie, wo John ist. Sie zeigt mit dem Finger auf ihn und sagt: »Dort.«
ln diesem Augenblick ist Alma ein Zeiger auf John. Wenn Sie sich einen Zeiger als etwas
vorstellen, das weiß, an welcher Stelle im Speicher sich ein Obj ekt befindet, haben Sie l es verstanden.
27
Kapitell Entwicklung mit Dashcode und Xcode
Diesem neu inst anziiert en Wi rbe 7 t i er-Obj ekt können dann Meldungen übergeben wer
den. Der vorstehende Codeausschnitt ent hält eine weit ere Meldung f ür das Obj ekt .
Sie best eht aus der Kombination i nitWithName und andAnzahlBeine. Dass es sich bei
dieser zweiteiligen Meldung um eine Meldung handelt, erkennen Sie daran, dass die Teile
und das neue Objekt gemeinsam von eckigen Klammern umschlossen sind, was angibt,
dass eine Meldung übergeben wird. Mehrteilige Meldungen werden durch Leerzeichen
getrennt, d.h., zwischen den beiden Teilen der Meldung steht ein Leerzeichen.
Außerdem sind die Meldungsteile und die damit übergebenen Wert e durch den Doppel
punkt ( :)verbunden. Jeder Meldungst eil kann mit maximal einem Parameter verknüpft
sein. Diese Meldung gibt einen Zeiger auf das neu zugewiesene Wi rbe 7 ti er-Obj ekt zu
rück, sodass es lokal zur späteren Benut zung gespeichert werden kann. ln Objective-C
werden diese Meldungsindikatoren sowohl f ür ein- als auch f ür mehrteilige Meldungen
als Selektoren bezeichnet, weil sie angeben, welche Met hoden des Obj ekt s der Compiler
auswählt und ausführt.
Keh ren Sie zu dem Xcode-Proj ekt Si mp l eExamp l e zurück, das Sie in Abschn itt 2 ange
legt haben. Sehen Sie sich die Methode appl i cat i onDi dFi ni sh l aunchi ng in der Datei
Si mp l eExamp l eAppDe l ega te . man, die die Vorlage erstellt hat. Kümmern Sie sich nicht
darum, was der Code macht, sondern betrachten Sie ihn als Beispiel für Meldungsüber
gabe.
1 - Cv oid) appl icationDi dFi ni sh l aunchi ng : CUIAppl icati on *) appl icati on {
2 II Fol gendes hi l ft bei der Feh l ers uche , sodass Sie " genau " wissen , wo I hre Ansichten pl atzi ert wer den ;
3 II sehen Sie "rot " , handel t es sich um das l eer e Fens t er . 4 llwindow. backg roundCol or = [ UICol or redCo l or ] ; 5 6 OuickConnectVi ewCon t roll er * aßrowserViewCont roll er= 7 [ [QuickConnectViewControl l er al l oc ]
i nit];
8 9 II dem Fens t er di e Ansicht Cr eateViewCont r ol l er al s
II Unt eransich t hi nzufügen 10 [window addSubview: aßrowserViewContr ol l er . view] ; 11 12 [window makeKeyAndVis i bl e ] ; 13
28
Die Struktur wn QuickConnectiPhone-Anwendungen in Objective-C
Zei le 8 sollte vertraut aussehen. ln diesem Fall wi rd kein Wi rbeltier erstellt, sondern ein
sogenannter OuickConnectViewControl lerzugewiesen und initia lisiert. Der Ausdruck
verwendet a ll oc- und i n it-Meldungen, wie Sie sie vorhin gesehen haben. Der Klasse
wird die a l l oc-Meldung übergeben, die einen Zeiger auf das neu zugewiesene Oui ck
ConnectViewControl ler-Objekt zurückgibt. An dieses neue Objekt wird über seinen
Zeiger die i ni t -Meldung gesendet.
Diese Meldung vollzieht dasselbe wie die mehrteilige Meldung i ni tWi thName:
andAnzah l Bei ne des Wi rbe 7 t i er-Objekts, ist j edoch wesentlich einfacher. Es handelt
sich nämlich um eine einteilige Meldung ohne Parameter. Weiter hinten in diesem Kapitel
erfahren Sie, wie lnitia lisierungs- und andere Methoden geschrieben werden, sodass Ihre
Objekte sie ausführen können, wenn sie eine Meldung erhalten.
Zei le 11 sendet eine Meldung an das wi ndow. Diese Meldung, addSubVi ew, ist mit einem
Parameter versehen, dem im Objekt a Br owser Vi ewContr o ll er enthaltenen vi ew
Attribut.
Sie haben damit ein einsetzbares Beispiel dafür gesehen, wie ein Obj ekt instanziiert, wie
ein Zeiger mit lokaler Gültigkeit auf dieses neue Objekt gespeichert, wie auf die Attribute
eines Objekts zugegriffen w ird und w ie Meldungen mit und ohne Parameter an Objekte
übergeben werden. Das ist der größte Teil der Obj ective-C-Grundlagen, die Sie kennen
müssen, um den Code in den QuickConnectiPhoneVorlagendateien zu verstehen. Als
Nächstes sollen Sie erfahren, wie Obj ective-C-Anwendungen aufgebaut werden.
1.4 DIE STRUKTUR VON QUICK(ONNECTIPHONE
ÄNWENDUNGEN IN ÜBJECTIVE-(
ln diesem Abschnitt geht es zwar um den grundlegenden Code in der Vorlage für
QuickConnectiPhone-Anwendungen, in allen anderen Implementierungen von Hybrid
anwendungen wird jedoch derselbe Ansatz verwendet. Sie können eine der vorhandenen
Implementierungen benutzen oder nach deren Studium eigene Versionen erstellen.
Stellen Sie sich vor, Sie besitzen eine Menge Antei le einer erfolgreichen Fi rma, was mög
licherweise zutrifft. Auf einer Aktionärsversammlung soll der Vorsitzende des Aufsichts
rats gewählt werden, aber Sie können nicht teilnehmen, wei l Sie gerade Urlaub auf den
Bahamas machen. Wie können Sie dennoch Ihre Stimme abgeben?
Beauftragen Sie j emanden, f ür Sie abzustimmen, wird diese Person als Ihr Stellvertreter
bezeichnet. Er besitzt die voll ständige Vollmacht, auf der Versammlung in Ihrem Namen
zu handeln. Er könnte auch als Ihr Delegat bezeichnet werden. Dieser Delegat würde Sie
seinen Prinzipal nennen, weil Sie der eigentliche Aktionär sind. Abbildung 1.7 veranschau-
29
Kapitell Entwicklung mit Dashcode und Xcode
licht diese Beziehung. iPhone-Anwendungen in Obj ective-C verwenden Prinzipal-Delegat
Beziehungen zwischen Objekten, bei denen das eine der Prinzipal und das andere der
Delegat ist.
.,. Abbildung 7.7: Die grafische Darstellung zeigt, Prinzipal dass ein Prinzipal einen Delegaten und ein Delegat
einen Prinzipal hat.
iPhone-Anwendungen in Objective-C verwenden diese Prinzipal-Delegat-Beziehung häufig.
Folgende Beziehungen sind besonders interessant:
> UIApplication/UIApplicationDelegate
> UIWebView/UIWebViewDelegate
> UIAccelerometer /U IAccelerometerDelegate
An dieser Stelle müssen Sie wissen, dass die Implementierung von Protokollmethoden f ür
diese Delegaten Ihrer Anwendung, Ihrer Ansicht oder Ihrem Accelerometer mittei lt, dass
nicht Sie selbst, sondern der Delegat bestimmte Ereignisse behandeln soll, wenn sie ein
treten. Jede Protokollmethode ist mit einem bestimmten Ereignis verknüpft.
PROTOKOLLE
Ein Protokoll ist eine Folge von Methoden, die einer Klasse hinzugefügt werden kann,
damit sie auf bestimmte Meldungen reagiert.
Vor dem Hintergrund dieses Prinzipal-Delegat-Konzepts werfen Sie jetzt einen Blick auf
eine Klasse, die ein Delegat ist. Es folgt die Headerdatei für die Klasse Simpl eExampl e
AppDe 1 ega t e, die angelegt wurde, als Sie in Abschnitt 2 die QuickConnectiPhone-Vorlage
verwendet und die Anwendung Si mp 1 eExampl e erstellt haben.
Objective-C-Headerdateien enden auf . h und deklarieren Klassen. Sehen Sie sich die
Headerdatei fü r die Klasse Si mp 1 eExamp 1 eAppDe l egate an, machen Sie sich aber keine
Gedanken über ihre lmplementierungsdatei:
1 //S i mpleExamp1eAppDe1egate.h 2 #import <U I Kit/ UIKit.h> 3 #import QuickConnectViewCon t ro1 1er.h " 4 5 @interface Simpl eExamp1eAppDelegate
<U I App l i cat i onDe1egate>
30
NSObject
Die Struktur wn QuickConnectiPhone-Anwendungen in Objective-C
6 7 I BOutlet UIWi ndow * wi ndow: 8 Qui ckConnect ViewController * browserVi ewCont r oller: 9 10 11 @property (nonatomic, r etai n ) UIWindow * wi ndow: 12 @property ( nonatomi c , ret ai n ) Qui ckConnectViewContro l l er
* browserViewControl l er; 13 14 @end
Betrachten Sie Zeile 5· Wenn Sie mit Java vertraut sind, lassen Sie sich nicht durch den
Indikator @i nt erfa ce in die Irre führen. Er bedeutet nicht, dass diese Klasse einer Java
Schnittstel le entspricht, sondern dass die Datei die Schnittstellendefinition f ür diese Klas
se ent hält . Die Headerdatei deklariert, welche Attribut e Si mp l eExamp l eAppDe l egate
hat, wie darauf zugegriffen w ird und welche Met hoden in der separaten Implementie
rungsdat ei ent halten sein sollen. Diese Klasse besitzt keine eigenen Methoden.
Was macht Zei le 5 denn nun, wenn es sich nicht um eine Schnittstellendefin it ion in Java
Manier handelt? Sie deklariert den Namen der Klasse, nämlich Si mpl e Examp l eApp
Oe l egate, und gibt mithilfe des Doppelpunkts als Trennzeichens an, dass sie von der Klas
se NSObj ect erbt. Deshalb handelt es sich um ein Obj ekt von NSObject und kann allevon
NSObject defin ierten Meldungen entgegennehmen. Wenn Sie sich die Klasse NSObj ect
in der API-Dokumentat ion im Xcode-Hilfemenü anschauen, sehen Sie, dass sie eine Me·
thode desc ri pt i on besitzt . Wei l Si mpl e Examp l eAppDe l egate durch Vererbung ein Ob
j ekt von NSObj ect ist, besit zt sie also auch eine Methode descri pti on.
Im Ansch luss an die Deklaration der Vererbung von NSObject lesen Sie <UI Appl ica
t i onDe legate>. Dies weist die Klasse Si mpl eExampl eAppDel egate an, sich als
Delegat fü r Ihre Anwendung zu verha lten, und gibt Ihnen die Möglichkeit, die Metho
den der U I App l i cat i onDe l egate-Prot okol lmeldungen in der Implementierungsdatei von Si mpl eExampl eAppDel egate umzuset zen. Eine davon ist appl icationDid
Fi ni shl aunchi ng.
Diese Methode wird aufgerufen, soba ld die Anwendung vollst ändig geladen und st art
bereit ist . Sie ermöglicht Ihnen, Ihre Anwendung anzupassen oder den Benut zer bei Be
darf um weitere Informationen zu bitten.
Zei le 11 im folgenden Code ent hält die QuickConnectiPhone-Definition von app l i ca
ti onDi dFi ni sh l aunchi ng in der lmplementierungsdatei. Sie beginnt mit einem M inuszeichen (-),das besagt, dass es sich um eine Obj ekt met hode handelt . ( voi d) be
deutet, dass die Methode nichts zurückgibt, und : ( U IApp l i cat i on *) gibt an, dass der
Methode ein Parameter des Typs U IApp l i cat i onübergeben w ird.
31
Kapitell Entwicklung mit Dashcode und Xcode
1 II 2 II Simpl eExampleAppDelegate .m 3 II Simpl eExample 4 II 5 #import "SimpleExampleAp pDelegate . h" 6 @impl ementation SimpleExampl eAppDel egate 7 8 @synthesize window: 9 @synthesize browse rViewControll er: 10 11 - Cvoid) appl icationDi dFin ish l aunching:CUIApplication *)
applica t ion { 12 II Dies hi lft bei de r Feh l ersuche, sodass 13 II Sie "genau " wissen, wo Ihre Ansichten pl aziert werden; 14 II sehen Sie "rot " , schauen Sie das l eere Fenster an, 15 II in Ih ren vertei l ten Anwendungen 16 II benutzen Sie Schwarz 17 II window. backgroundColo r = [UICol or redCol or]: 18 19 QuickConnectViewControl l er *aßrowserV iewController=
[[QuickConnectViewControl l er al loc] i nit ] ; 20 II dem Fenster die Ansicht aßrowserViewCont rol l er 21 II al s Unteransicht hinzufügen 22 [window addSubview:aßrowse rViewContro l l er.view]; 23 [window ma keKeyAndVisibl e]; 24
Diese Methode app l i cat i onDi d Fi nish Launch i ng wi rd als Teil der Delegatklasse für Ihre Anwendung automatisch aufgerufen, wenn die Anwendungfertig geladen ist. Deshalb kann sie dazu verwendet werden, andere Elemente zu instanziieren, die möglicherweise in der Anwend ung benötigt werden. in diesem Fa ll sehen Sie in Zei le 19 die Zuweisung und lnitia lisierung der anderen Klasse (Oui c kConnect Vi ewCont roll e r), die durch QuickConnect-Vorlage in Ihre Anwendung integriert wurde.
iPhone-Anwendungen sind ansichtsbasiert, und jedes Objekt von U I Wi ndow oder U IVi ew ka nn U I Vi ew-Objekte ent halten. Deshalb ist es möglich, eine Ansicht in einer Ansicht unterzubringen. Von einer derart igen Gestaltung ist fü r iPhone-Anwendungen jedoch abzu-
32
Webinhalt einbetten: QuickConnectiPhone
raten. Anstelle dieses hierarchischen Ansatzes tauscht die Entwicklergemeinde meistens
nach Bedarf des Benutzers auf möglichst hoher Ebene untergeordnete Ansichten gegen
einander aus.
Außerdem führt der Austausch von Unteransichten zu einer flacheren, wen iger komple
xen Ansichtenstruktur in Ihrer Anwendung. Dankenswerterweise hat die Vorlage, die Sie
zum Erstellen der Anwendung benutzt haben, genau die richtige Anzahl von Ansichten
innerhalb von Ansichten untergebracht, damit Sie Ihren Webinhalt darstellen können. Wie
Sie später sehen, ist in der Ansicht, die gerade in das Fensterobjekt eingefügt wurde, eine Web-Unteransieht enthalten.
Die Klasse Qu i c kConnectV i ewCon t r o 11 er enthält das eigentliche Ansichtsobjekt, das
Ihren Inhalt als eines seiner Attribute im Fenster Ihrer Anwendung anzeigt. Dieses Attribut
muss dem Hauptfenster als Unteransicht hinzugef ügt werden, was in Zeile 22 geschieht.
Die Klasse Qu i ckConnectVi ewCon t r ol l er enthält nicht nur die lnhaltsansicht, son
dern ist außerdem ein Delegat fü r die GPS-Orts-, Accelerometer-, WebView- und andere
Ereignisa rten.
1.5 WEBINHALT EINBETTEN: QUICK(ONNECTIPHONE
Um in Ihrer Anwendung Webinhalt w ie Objective-C-Anwendungen oder einfache Web
seiten anzuzeigen, müssen Sie die Klasse U I WebVi ew benutzen. Alle Implementierungen
von Hybrida nwendu ngen, a I so auch QuickCon nectiPhone, verwenden diese Klasse. Wollen
Sie in einer Anwendung ein toll es Schriftsteuerelement haben -d.h. mehrere Schriftarten und/oder Größen und Farben -, müssen Sie mit U IWebVi ew arbeiten oder den Text mit viel
Mühe selbst zeichnen. Die Klasse U IWebVi ew bietet den wesentlich einfacheren Weg, weil
sie außer Obj ective-C auch HTML und CSS interpretiert, was Ihnen die Möglichkeit gibt,
komplexe Text- und sonstige Layouts zu erstellen.
Die Klasse U IWebV i ew ist eigentlich ein Wrapperfür die Darstellu ng durch das WebKit, der
von dem Safari-Browser, Adobe Air-, Android- und Nokia-Telefonen sowie einigen anderen
Anwendungen benutzt wird, darunter die zu OS X gehörenden w ie Mail. Auch Dashcode
verwendet das WebKit-Modul in großem Umfang.
Wie in den beiden vorhergehenden Abschnitten erwähnt, muss das U I WebVi ew-Obj ekt
einer anderen Ansicht in der Anwendung als Unteransicht hinzugef ügt werden, um eine
Webansicht in die Anwendung einzubinden. Dazu dient die Methode l oadVi ew der Klasse
QuickConnectVi ewCont r oll er.
33
Kapitel l Entwicklung mit Dashcode und Xcode
Diese Methode enthält eine Reihe von Elementen, die es ermöglichen, in einer auf Objec
tive-C basierenden Anwendung Verhaltenweisen auszudrücken. Dazu gehört beispiels
weise der Code, der die Benutzeroberfläche Ihrer Anwendung auf Bi ldschi rmgröße skaliert.
Diese Fähigkeit ist standardmäßig auskommentiert, weil die Benutzeroberfläche so ge
staltet werden sollte, dass sie auf den Bildschirm passt.
Der interessante Teil von l oadVi ew ermöglicht die Anzeige der Oberfläche, die Sie weiter
vorn in diesem Kapitel in Dashcode erstellt haben. Der folgende Codeausschnitt zeigt, wie
das iPhone diesen Inhalt in die Anwendung einfügt. Er beginnt mit der Berechnung von
Größe und Ursprung für die Anzeige des UI WebVi ew-Objekts. Dazu fragt er Größe und
Position des Anzeigerahmens der Anwendung ab.
Diese Informationen stehen in der als webFramebezeichneten Struktur CGRect, die durch
Senden der Meldung app l i cati on Frame an den Hauptbildschirm der Anwendung er
stellt wird. Sämtliche CGRect-Strukturen bestehen aus zwei Elementen: einem Ursprung
mit dem Namen CG Po i nt, der die x-und die y-Koord inate der linken oberen Ecke angibt,
und der Angabe CGS i ze mit der Größe des Rechtecks in Höhe und Breite:
CGRect webFrame = [ [U I Screen mainScreen] app l i ca t ion Frame]; webFrame .or igi n.y -= 20 .0:
x- und y-Koordinate, Breite und Höhe einer CGRect-Strukt ur sind Fließkommazahlen, die
Pixelwerte aufnehmen. Die zweite Zeile des vorstehenden Codes zeigt, wie der aktuelle in
derVariablen web Fra me gespeicherte Wert f ür die senkrechte Position geändert w ird. Sie
versch iebt den Ursprung um 20 Pixel nach oben, was erforderlich ist, um den in der Ansicht
vorhandenen Leerraum für eine nicht vorhandene Werkzeugleiste oben im Anzeigefenster
zu überdecken.
Diese Werkzeugleiste ist in zah lreichen St andardanwendungen zu finden, beispielsweise
in Einstellungen, mit denen Sie Ihre Wi-Fi-Verbindungen konfigurieren. Sie wurde aus den
Vorlagen entfernt, um den beschränkten Bi ldschirmplatz für die Anwendung bestmögl ich
nutzen zu können. Hätten Sie gern, dass diese Leiste als Navigationsleiste das Vor- und
Zurückverhalten aufweist, sollten Sie dies mithilfe von Dashcode als Tei l ihrer Anwendung
real isieren.
Stehen die gewünschte Position und Größe für die Anzeige Ihres Webinha lts in der Varia
blen web Frame, können Sie damit ein U I WebVi ew-Obj ekt mit dem Namen aWebVi ew ini
t ialisieren (siehe Zeile 1 und 2 des folgenden Codes). Beachten Sie die Ähnlichkeit mit der
Zuweisung an Quic kConnec t Vi ewControll er, die Sie weiter vorn in diesem Kapitel
34
Webinhalt einbetten: QuickConnectiPhone
untersucht haben. Die wesentlichen Unterschiede liegen darin, dass die a l l oc-Meldung
an die Klasse UI WebVi ew gesendet wird und dass das UI WebVi ew-Objekt, das gerade
eine Zuweisung erha lten hat, die Meldung i ni tW i thFrame empfängt und die Struktur
web Frame erhält, die im vorigen Codeausschnitt erstellt und geändert wurde. Das Objekt
aWebV i ew wird entsprechend den Positions- und Größenwerten in webFrame angelegt:
1 UIWebV iew * aWebView = [ [ UIWebView alloc ] 2 i nitWithFrame:webFrameJ: 3 self .webView = aWebView : 4 aWebVi ew.autoresizesSubv i ews = YES: 5 aWebVi ew.autoresiz i ngMask=( UIV iewAutoresi zi ngFlexi bleHeight 6 1 UIV iewAutoresi zingFlex i bleWi dth); 7 //den webV i ew- Delega ten für die Webans icht au f sich se l bs t setzen 8 [ aWebView setDel egate:sel f ] ;
Mit dem Code in Zei le 3 wird das neue U IWebVi ew-Objekt im Attribut webVi ew der Klas
se Qu i c kconnectWebVi ewCont r ol l e r gespeichert, sodass andere Methoden der Klasse
später daraufzugreifen können. Das wird bei Verwendung der in Kapitel4, »GPS, Beschleu
nigung und andere native Funktionen mit QuickConnect«, beschriebenen Fähigkeiten zur
Besch leunigung, GPS-Lokalisierung usw. wichtig.
Zei le 5 und 6 geben an, wie viel Flexibi lität das Objekt aWebVi ew besitzt, um sich selbst
neu zu zeichnen. Vermeiden Sie es nach Möglichkeit, Unteransichten hinzuzufügen. Zeile
4 besagt, dass sich die Größe von Unteransichten gemeinsam mit der von aWebVi ew än
dert. Wenn sich die Breite von aWebVi ew aufgrundeiner Drehung ändert, soll sich somit
die Breite aller Unteransichten um denselben Skalierungsfaktor ändern.
Zei le 5 und 6 besagen, dass sich auch Breite und Höhe von aWebVi ew ändern. Wenn das
iPhone gedreht wird, ist es üblich, dass die aktuelle Ansicht ins oder aus dem Querformat
wechselt und sich an die neue Breite und Höhe anpasst, die das Gerät hergibt. Werden
die beiden Zei len entfernt oder auskommentiert, wird die Anwendung trotzdem gedreht,
aber Breite und Höhe von aWebVi ew bleiben bestehen. Dadurch erscheint im Querformat
rechts von den Anwendungen ein großer Leerraum. Sie sollten äußerst selten zu lassen,
dass die Ansicht Ihrer Anwendung ohne Größenanpassung gedreht wird.
Zei le 8 des vorstehenden Codes sendet aWebVi ew eine Meldung, dass das aktuelle
Qu i ckConnect Vi ewCont roll er-Objekt se l f als Delegat des Objekts aWebVi ewfungiert.
Dies ermöglicht die Implementierung mehrerer optionaler Methoden von UIWebView-
35
Kapitell Entwicklung mit Dashcode und Xcode
Oe l egate in der Klasse Qu i c kConnect Vi ewContro ll er. ln Tabelle 1.1 sind diese Metho
den zusammengestellt.
Fügen Sie der Klasse Qui c kConnectVi ewCont ro l l er bei Bedarf beliebige dieser optiona
len Methoden hinzu.ln derVorlagesind bereitswebVi ew: s hou l dSta r tloadWi t h Reques t,
webV i ew:DidStartload, webV i ew:Did Fi ni shl oad und webView :d i dFail l oad
Wi th Error enthalten.
Nach der Vorbereitung von aWebVi ew müssen Sie jetzt angeben, welcher Inhalt geladen
werden soll, und dann den Ladevorgang auslösen. Dazu muss der Speicherort der Datei
i ndex . htm l in den Ressourcen der Anwendung ermittelt werden. Glücklicherweise ver
fügt die Klasse NSBundl e, die Ihre Anwendung auf der Festplatte des Gerätes repräsen
tiert, über die Methode pathForResource: ofType, wie Sie in Zeile 3 und 4 des folgenden
Codeausschnitts sehen.
Die Methode path ForRes ource : ofTy pe übernimmt als Parameter zwei Strings. Der ers
t e ist der Name der Datei, der als index des Strings gezeigt wi rd, der zweite die Erweite
rung html des Dateinamens. Als Ergebnis dieses Methodenaufrufs wi rd ein vollständiger Pfad zu der Datei auf Ihrem iPhone erstellt und in der lokalen Variablen fi l ePa t hst ri ng
abgelegt. Anschließend kann aus dem String ein Objekt erstellt werden, das den URL zu
der Datei darstellt, sowie das Objekt aRequest der Klasse NSURLRequest, das für das zu
ladende Element steht (siehe Zeile 7 und 8).
1 //den Pfa d der Datei i ndex . html fi l e im 2 //Verzeichnis Resources ermitteln 3 NSString *f i l ePathStr i ng = [ [ NSBund l e mainßundl e] 4 path Fo r Resource :@"i ndex " ofType:@" html " ]; 5 //den URL und die Anforderung für di e Datei i ndex.html erstell en 6 NSURL *aURL = [ NSURL f i l eURLWith Pat h: fi l ePat hStr i ng ]; 7 NSURLRequest *aRequest = [ NSURLRequest 8 requestWithURL: aURL]; 9 //die Datei i ndex. html in die Webans icht l aden 10 [ aWebVi ew l oadRequest:aRequest]; 11 //die Webansicht i n die I nha l tsans i cht einfügen 12 [ contentView addSubv i ew:aWebVi ew];
36
Webinhalt einbetten: QuickConnectiPhone
Methodensignatur Zeitpunkt des Aufrufs Parameter
- ( BOO L)webVi ew: Direkt bevor die webVi ew- die Ansicht,
CU IWebView *) webView Ansicht beginnt, die im Begriff ist, Inhalt
shouldStartloadWithRequest: Inhalt zu laden zu laden
CNSURLRequest *) request request- der
nav igat ionType: Speicherort des zu
CU IWebViewNav igationType) ladenden Inhalts
nav igat ionType na vi gat ionType-der
Typ der Benutzeraktion,
die das Laden der Seite
auslöst
Optionen für
UIWebViewNaviga -
t i onType-
Li nkCl i cked,
FormSubmit ted,
BackForward, Re l oad,
FormResubmitted
und Other
- Cvoid)webViewDidStart Load: Nachdem die webVi ew- die Ansicht,
CU I WebView *) webView Ansicht begonnen die den Inhalt lädt
hat, Inhalt zu laden
- Cvoid)webViewDidFinishload: Nachdem die Ansicht webVi ew- die Ansicht,
CU I WebView *) webView den Ladevorgang die den Inhalt lädt
erfolgreich
abgesch lossen hat
- Cvoid)webView: Wenn das Laden von webVi ew- die Ansicht,
CU I WebView *) webView Inhalt feh lsch lägt die versucht, den Inhalt
didFai l loadWith Error: zu laden
CNSError *) error Error- ein Fehlerob-
jekt, das für den aufge-
tretenen Fehler steht
Tabelle 1.1: Delegaten der U/WebView-API
37
Kapitel l Entwicklung mit Dashcode und Xcode
in Zeile 6 w ird dem NSURL-Objekt die Meldung fi l eURLWi thPath übergeben. Da eine
Datei direkt von der Festplatte geladen wird, ist dies die passende Meldung. Es ist das
Einzige, was für QuickConnectiPhone-Hybridanwendungen benötigt wird. Verwenden Sie
j edoch eine andere Implementierung und laden eine Seite direkt aus dem Web, heißt die
Meldung URLWithStri ng. Sie wird mit einem vollständigen URL als Parameter überge
ben, etwa http://www.mobile-dev.de.
Nachdem das NSURLRequest-Objekt vol lständig erstellt ist, w ird das eigentliche Laden
des angeforderten URLs ausgelöst, indem die Meldung l oadReques t an das U IWebVi ew
Objekt aWebVi ew gesendet wird. Als einziger Parameter dieser Meldung wird das NSURL
Request-Objekt aReques t übergeben.
Nachdem eine Anforderung geladen wurde, wird aWebVi ew in das Hauptinhaltsfenster
eingefügt, indem diesem die Meldung addSubvi ew mit dem U IWebVi ew-Objekt als Pa ra
meter gesendet wi rd. Geschieht dies nicht, w ird die Seite geladen und ist vollständig aktiv,
w ird jedoch nicht angezeigt.
1.6 ZUSAMMENFASSUNG
Um iPhone-Hybridanwendungen zu schreiben, benötigen Sie einen kleinen Obj ective-C
Wrapper für Ihre aus HTML, CSS und JavaScript bestehende Anwendung. Dashcode ist ein
leistungsfähiges Werkzeug, mit dem Sie schnell und einfach dynamische Objective-C-An
wendungen erstellen können, die sich mithilfe eines solchen Wrappers einbetten lassen.
Die QuickConnect iPhone-Anwendungsvorlagen f ür Dashcode und Xcode beschleunigen
die Entwicklung von Anwendungen, indem sie den sich w iederholenden Code, der in
Hybridanwendungen benutzt wird, in Ihr Proj ekt einbinden. Wie die Kapitel 3, 4, 5, 6 und
7 zeigen, stellen die Xcode-Vorlagen den Objective-C- und den JavaScript -Code bereit, den
Sie fü r Hybridanwendungen mit Objective-C-Zugriff auffolgende Dinge brauchen:
38
Zusammenfassung
1.6.1 QuickConnectiPhone
> Accelerometerdaten
> GPS-Ortsdaten
> Gerätevibration
> Benutzerdefinierte Systemtöne
> Audioaufzeichnung und -Wiedergabe
> Anzeige von Standardpickern für Datum und Datum/Uhrzeit
> SQLite-Zugriff während der Ausführung der Anwendung auf die Datenbanken, die
mit Ihrer Anwendung ausgeliefert werden, und diejenigen im UI We bVi ew-Objekt
M it den Dashcode- und Xcode-Vorlagen können Sie Anwendungen f ür das iPhone schnel
ler erstellen als j emals zuvor.
39
JavaScript-Modularität und iPhone-Anwend ungen
Beim Programmieren in JavaScript fallen einem normalerweise zwei Wendungen ein:
browserübergreifende Kompat ibilität und Komplexität. Dieses Kapitel zeigt Ihnen, w ie Sie
in iPhone-Hybridanwendungen Komplexität vermeiden, und gibt Ihnen Quellcode an die
Hand, der komplexe Verhaltensweisen schnell und einfach umsetzt, ohne die Flexibil ität
zu opfern. Bei iPhone-Web-Apps brauchen Sie sich keine Gedanken über browserüber
greifende Kompatibi lität zu machen, weil nur das Safari-Modul WebKit verwendet wi rd.
Das vereinfacht es sogar, interessante und zufriedenstellende JavaScript-Anwendungen
zu schreiben.
2.1 MODU LARITÄT
Das Konzept der Modularität gibt es sowohl in den IT-Branchen als auch in anderen schon
lange. Das Wesen des Konzepts gibt die Wendung »Erstellung aus austauschbaren Teilen«
wieder. Handelt es sich dabei um wi rklich austauschbare Module, müssen sie einander
ohne oder nahezu ohne Änderungen an den Elementen ersetzen können, die mit ihnen zusammenarbeiten. ln Programmen ist dies normalerweise eine gemeinsame definierte
API, die sich nicht ändert.
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Die Unterhaltungsbranche sähe chaot isch aus, wenn jeder Fi lm auf einem anderen Medium
produziert würde, weil dann für jeden ein anderer Projektor benötigt würde. Standardisier
te ein Autohersteller die Verbindung seiner Motoren mit dem Getriebe nicht, müsste jede Motor-Getriebe-Kombination von Hand entworfen werden. Die Kosten schnellten raketen
artig in die Höhe, und die Qualität könnte leicht zusammenbrechen.ln der Softwarebranche
hat es zah lreiche Versuche gegeben, modularen, wiederverwendbaren Code zu schreiben.
Heute werden diese als Framewerks bezeichnet.
r MODULDEFINITION
Ein Modul muss zwei Charakteristika erfüllen: engen Zusammenhalt und lose Kopplung.
Enger Zusammenhalt bedeutet, dass das modulare Element eine klar defin ierte Rolle
spielt und alles Notwendige tut, um diese auszufüllen. Es hat einen Existenzzweck und
handelt danach, erledigt beispielsweise eine bestimmte Aktivität.
Lose Kopplung bedeutet, dass das Modul nicht darauf angewiesen ist, die interne
Funktionsweise anderer Module zu kennen, und dass andere Module seine interne
Funktionsweise ebenfalls nicht kennen. Dazu ist es notwendig, eine leistungsfähige
Schnittstelle zu erstellen und zu benutzen.
Sind diese beiden Charakteristika erreicht, ist ein Modul geboren.
Ein Steak ist ein Modul, Spaghetti dagegen nicht.
Framewerks sind interessant zu untersuchen. Normalerweise besteht bei ihnen ein Kom
promiss zwischen der Leichtigkeit der Verwendung und der Flexibi lität. Arbeitet der Ent
w ickler des Framewerks nicht sorgfä ltig, kann er die Erledigung unw icht iger Dinge mit
dem Framewerk einfach, die Erled igung dessen, was der Entwickler oder Programmierer
braucht,jedoch schwierig machen.
Häufig wi rd beim Versuch, ein Framewerk einfach einsetzbar und flexibel zu gesta lten,
die Ska lierbarkeit der Ausf ührung geopfert, was bei Ruby on Rails der Fall ist. Es lässt sich
w underbar einsetzen, aber nicht auf Unternehmensgrößen mit großen Hardwaremengen
in Clustern skalieren, was die Supportfäh igkeit reduziert und den Aufwand erhöht . Wie kann ein Framewerk also skalierbar, einfach einset zbar und flexibel gestaltet werden? Die
Antwort liegt in gut angewandter und hoch ausgereifter Modularität.
Bestimmte Arten von Modulen tragen, auch wenn dies normalerweise weder gelehrt noch
hervorgehoben wi rd, zurVereinfachungder Softwareentwicklung bei. Diese in gewisser Wei
se geheimen Module werden als Frontcontroller und Anwendungscontroller bezeichnet.
Die Beispiele in diesem Kapitel zeigen Ihnen, w ie Sie sie schreiben und einsetzen und w ie
sie die Erstellung von Anwendungen einfacher und schneller machen können.
42
Das JavaScript-Framework von QuickConnectiPhone
2.2 DAS JAVASCRIPT-FRAMEWORK VON QUICK(ONNECT
IPHONE- EIN BEISPIEL FÜR MODULARITÄT
Das JavaScript-Framework in den Dashcode- und Xcode-Vorlagen ist so gestaltet, dass es
die Prozessor- und Speichernutzung minimiert, aber dennoch einfach einsetzbar bleibt.
Da es hochgradig modular ist, erledigt jede Komponente eine bestimmte Sache, und zwar
gut und schnel l.
Die Gesta ltung beruht auf einem Paradigma von Befehl und Reaktion. Senden Sie einen
Befehl, führen die Module die notwendigen, mit diesem verknüpften Funktionen aus. Ab
bi ldung 2.1 zeigt den Fluss der Verarbeitung durch eine Anwendung auf der Grundlage
dieses Entwurfsansatzes. Die Verarbeitung beginnt mit Schritt 1 und folgt den numme
rierten Pfeilen durch das Framework.
Validierungssteuerfunktion
I Anforderung
~ Frontcontroller
• 12
Anwendungscontroller
Unternehmenssteuerfunktion
5
Datenbankzugriffsobjekt
Ansichtssteuerfunktion
~ Abbildung 2.1: Der Verarbeitungsfluss für einen einzelnen Befehl
43
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Die einzigen Elemente im Fluss, die noch nicht erstellt wurden, sind die für das Verhalt en
Ihrer Anwendung spezifischen Va lidierungs-, Unternehmens- und Ansichtssteuerfunktio
nen. Beispiele für diese anwendungsspezifischen Module finden Sie im gesamten weite
ren Verlauf des Buches.
Um Benutzereingaben zu validieren, verwenden Sie Va lidierungssteuerfunkt ionen (Validation Control Functions, VaiCF). Mit Unt ernehmenssteuerfunktionen (Business Control
Functions, BCF) rufen Sie Daten aus einer Datenbank, von einem Webserver oder aus einer
anderen Quelle ab oder speichern sie. Ansichtssteuerfunktionen (View Control Functions,
VCF) dienen zur Aktualisierung des Benutzerbildschirms.
Möglicherweise wollen Sie Benutzerdaten mith ilfe einer formularähnlichen Oberfläche erheben, die eine SuBMIT-Schaltfläche enthä lt. Diese Informationen können Sie anschlie
ßend in der SQLite-Datenbank speichern und dem Benutzer mitteilen, dass die Speiche
rung erfolgreich war.
Dazu erst ellen Sie drei Steuerfunktionen: eine Valid ierungssteuerfunktion, um sicherzu
st ellen, dass die eingegebenen Dat en die Minimalstandards erfü llen, die Ihre Anwendung
benötigt, eine Unternehmenssteuerfunktion, um die Daten in der Dat enbank abzu legen,
und eine Ansicht ssteuerfunktion, um eine sichtbare Erfolgsmeldung auszugeben.
Nicht die gesamte Funktionalität muss mit allen drei Art en von Steuerfunkt ionen ver
knüpft sein. Eine Anwendung w ie ein Spiel braucht normalerweise nicht j edes Mal, wenn
der Benut zer ein Verha lten auslöst, eine Validierungsst euerfunktion.
Abbildung 2.1 macht deut lich, dass nicht alle drei Steuerfunktionen mit einander kommu
nizieren müssen. Die Module des Frameworks sind so gesta ltet, dass sie dies erledigen. Sie
brauchen Ihre Steuerfunkt ionen lediglich zu schreiben und mit Befehlen zu verknüpfen.
Aufgrund der Gest altung benötigt jede St euerfunkt ion nur wenige Zei len Code und ist
direkt einsatzfähig.
Da die Gestalt ung modular ist, können Sie problemlos das Konzept der Arbeitst eilung an
wenden. Teilen Sie die Erst ellung dieser St euerfunktionen in einem Team nach Befehl oder
Typ auf, kann die eigenständige Arbeit schnell fortschreit en. Weit ere Informationen dazu, was die einzelnen Steuerfunktionen sind und w ie sie geschrieben werden, finden Sie in
Abschnitt 4 und 5·
Korrekt erst ellt e Steuerfunktionen lassen sich f ür mehrere Befehle w iederverwenden. Sie
können beispielsweise mehrere Befehle benut zen, um denselben Bildschirmbereich zu
akt ualisieren. Die Gesta lt ung ermöglicht Ihnen, eine Ansicht ssteuerfunkt ion zu verknüp
fen, die den betreffenden Bi ldschirmbereich mit einer beliebigen Anzahl von Befehlen
akt ualisiert.
44
Das JavaScript-Framework von QuickConnectiPhone
Wie in Tabelle 2.1 gezeigt, ist der Frontcontroller das Tor, das alle Anforderungen zur Aus
führung passieren müssen. Dadurch, dass alle Anforderungen durch den Frontcontroller
gezwungen werden, w ird es wesentlich einfacher, die Reihenfolge der Ausführung in der
Anwendung im Voraus festzu legen.
Methodensignatur Rückgabe Parameter
handl eResultCaCmd, void aCmd- Ein eindeutigerString mit dem zu
pa ramArray) verarbeitenden Verhalten, zum Beispiel »displ ayßlog Entries«
pa ramArray -ein optionaler Parameter,
der aus einem Arrayvon Variablen besteht,
die möglicherweise bei der Vera rbeitung
benötigt werden
Tabelle 2.1: Die Frontcontroller-API
Der Frontcont roller hat viel Ähnlichkeit mit einer Mauer um eine ant ike befestigte Stadt:
Es gibt nur einen Weg hinein und hinaus. Durch Reduzierung der möglichen Einfal lspunk
te in die Stadt lässt sie sich einfacher verteidigen, und die Bürger können sicherer leben.
Die Auf nahme eines Frontcontrol lers in Ihre Anwendung macht diese leichter schützbar.
Die Implementierung des Frontcontrol ler-Moduls im JavaScript-Framework von QuickCon
nectiPhone ist in der Funktion ha nd l eRequest untergebracht, die Sie in der Datei Quick
Connect . j s fi nden, die in Xcode in der Gruppe OCi Phone bzw. in Dashcode im Ordner
QCi Phone Ihrer Anwendung steht. Wenn Sie diesen Code analysieren, erkennen Sie, w ie die
Funktionen fü r die Sicherheit und die Reihenfolge der Ausführung funkt ion ieren.
Wenn die Funktion hand l eRequest aufgerufen w ird, werden ihr ein Befehl und ein
Array mit Pa rametern übergeben. Der Parameter command ist erforderlich, der Pa rameter
pa ramArray dagegen optional.
Der folgende Code, Zeile 17 bis 20 der Datei funct i on s . j s der Anwendung s i mp l eCa l c,
ist ein Beispiel für den Aufruf der Funktion handle Request in Reakt ion auf eine Benutzerakt ion. Hier klickt der Benutzer auf die Schaltfläche mit dem Addit ionssymboLAbbi ldung 2.2
zeigt die Anwendungs i mp l eCa l c, nachdem der Benutzer auf M umPLY geklickt hat.
45
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
r HINWEIS
Sie finden diese und weitere in diesem Buch verwendete Beispielanwendungen als
Dashcode-Projekt innerhalb des von Ihnen heruntergeladenen QuickConnectFamily
Paketes in dem Ordner iPhone Examples.
f unction add( event ) {
handleRequest ( ' math' ,new Array( '+' )) ;
Als erster Parameter w ird der Befehl ma t h übergeben, als zweiter ein Array, das lediglich
das Zeichen +enthält. Die Verwendung eines Arrays mag in diesem Fal l unnötig erscheinen, aber weil der Entwurf als zweiten Parameter ein Arrayverlangt, ist er flexibler, wie Sie
weiter hinten in diesem Kapitel sehen.
Simple Calculator A B
~ ~
oiiifiiü 3 4' 5 • 15
~ Abbildung 2.2: Die Beispielanwendung simpleCalc zeigt das Ergebnis der Betätigung der Schaltfläche Multiply.
Die Funktion add ist der onc l i c k-Listener für eine Schaltfläche. Wird die damit verknüpf
te Schaltfläche ausgewählt, werden alle dem Befehl math zugeordneten Validierungs-,
Unternehmens- und Ansichtssteuerfunktionen ausgeführt und ihnen das Parameterarray
übergeben. Beachten Sie, dass die Listener-Funktionen s ub t ra ct, mult i p l y und d i v i de
denselben Befehl wie add verwenden, im Array aber ein anderes Zeichen übergeben.
46
Das JavaScript-Framework von QuickConnectiPhone
ln diesem Fal l verwendet die Anwendungfür jede Funktiona lität denselben Validierungs-,
Unternehmens- und Ansichtssteuercode wieder. Es ist auch möglich, in jedem Listen er einen anderen Befehl und andere Unternehmenssteuerfunktionen zu benutzen, die Validie
rungs- und die Ansichtssteuerfunktion jedoch wiederzuverwenden. ln diesem Fall ist für
jede gewünschte Art von Arithmetikoperation eine eigene Unternehmenssteuerfunktion
erforderlich, die jedoch ähnlich aussieht. Daher wurde die Entwurfsentscheidung getrof
fen, nur eine Unternehmenssteuerfunktion zu schreiben.
Abbildung 2.3 zeigt den Anwendungsfluss im Beispiel s i mp l eCa l c bei Betätigung
einer Arithmet ikschaltfläche der Oberfläche durch den Benutzer. in diesem Fall werden
zwei Va lidierungssteuerfunktionen ausgeführt, um zu ermitteln, ob die Fortsetzung der
Ausführung gefahrlos ist. Denken Sie daran, dass der hier gezeigte modulare Entwurf die
Reihenfolge der Funktionsaufrufe erzwingt.
Die erste Validierungssteuerfunktion prüft, ob die beiden vom Benutzer eingegebenen
Werte Zah len sind. Die zweite, d i v i s i on By Ze roVa l CF, sorgt dafür, dass keine Division
durch null stattfindet.
Befehlsfluss
( checkNumbersVaiCF
( divisionByZeroVaiCF
( calculateSolutionBCF
( displaySolution VCF
) ) ) ) .,.. Abbildung 2-3: Ausführungsreihenfolge der dem
Befehl math zugeordneten Steuerfunktionen
Nach der Übergabe beiderValidierungen wird die Funktion cal cu lateSolu t ions BC F
aufgerufen, die die vom Benutzer angeforderte Berechnung durchführt. Anschließend
gibt die Funkt ion d i s p l aySo l ut i on VC F das Ergebnis aus (siehe Abbildung 2.2).
Scheitert die Anforderung j edoch an einer der beiden Validierungssteuerfunktionen, bie
tet der modulare Entwurf Steuerfunktionen, die diese Situation handhaben können.
Fehlersteuerf unktionen (Error Control Functions, ECF) sind als Steuerfunktionen zur Hand
habung von Fehlersituat ionen definiert . Schlägt eine Validierungsfunktion fehl, wi rd die
Funktion entry ECF aufgerufen (siehe Abbildung 2-4). Sie informiert den Benutzer über
einen Feh ler bei einer oder mehreren Eingaben.
47
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
"math "
( checkNumbersVaiCF
( divisionByZeroVaiCF
} "badNum"
H entryECF )
} "divZero" ----------"
( calculateSolutionBCF
( displaySolutionVCF
) )
.,.. Abbildung 2.4: Der Befehlsfluss des Befehls math
Wie w ird denn nun der Befehl math den vier Befehlsfunktionen zugeordnet, die ausge
führt werden müssen? ln der QuickConnectiPhone-lmplementierung dieser Gestaltung
werden vier Hilfstunkt ionen bereitgestel lt. Jede ordnet einen Befehl einer Steuerfunktion
zu, w ie Tabel le 2.2 zeigt.
Methodensignatur Rückgabe Parameter
Ma pCommandToVa l CF(command , void c omma n d -ein eindeut iger Stri ng m it
va l ida ti onCont ro l Function) dem zu verarbeitenden Verha lten,
zum Beispiel mat h
va l ida ti onCont ro l Function
-eine Va lidierungssteuerfunkt ion,
die ausgeführt wi rd, wenn die
Funkt ion hand l eRequest den Befehl
empfängt
Ma pCommandToBCF(command, void c omma n d -ein eindeut iger Stri ng m it
bus inessContro l Func t ion) dem zu verarbeitenden Verha lten,
zum Beispiel mat h
bus i nes sCon t ro l Func t ion- eine
Unternehmenssteuerfunktion, die
ausgeführt wi rd, wenn die Funkt ion
hand l eReques t den Befehl
empfängt
48
Das JavaScript-Framework von QuickConnectiPhone
MapCommandToVCFCcommand, void comma nd-ein eindeutigerString mit
viewControlFunction ) dem zu verarbeitenden Verha lten,
zum Beispiel ma th
viewContro l Function-eine
Ansichtssteuerfunktion, die
ausgeführt wird, wenn die Funktion
handl eRequest den Befehl
empfängt
MapCommandToECFCcommand, void comma nd-ein eindeutigerString mit
errorControl Function) dem zu verarbeitenden Verhalten,
zum Beispiel d i vZero
er ro rCont ro l Func t ion-eine
Fehlerf unktion, die ausgeführt wird,
wenn die Funktion hand l eRequest
den Befehl empfängt
Tabelle 2.2: Die API Mapping Function
Der folgende Code, Zeile 24 bis 27 der Datei mappi ngs . j s, zeigt, wie die Zuordnung von
Befehlen zu Steuerfunktionen f ür den Befehl math und die beiden Fehlerbefehle badNum
und di vZero erfolgt.
//e i nen Befehl mehreren Fun ktionen zuordnen mapCommandToVa l CFC ' math ' ,checkNumbersVa l CF); mapCommandToVa l CFC ' math ' ,divisionByZeroVa l CF); mapCommandToBCFC ' math ' , ca l cu l at eSo l utionBCF); mapCommandToVCFC ' math ' , displ aySol utionVC F); //mehrere Befehl e, die einer Fun ktion zugeordnet sind mapCommandToECFC ' badNum ' , entryECF); mapCommandToECFC ' divZero ' , entry ECF);
Ein gut gestalteter Frontcontroller muss nur einmal geschrieben werden und kann dann
in mehreren Anwendungen verwendet werden. Der konkrete Entwurffür Front- bzw. Anwendungscontroller in diesem Kapitel bietet auch eine einfache Möglichkeit, das spezifi
sche Verhalten Ihrer Anwendungen zu gestalten.
Da dieser vollständ ige Entwurf dafür sorgt, dass zuerst alle Validierungssteuerfunkt ionen
ausgeführt werden und dann alle Unternehmens- und Ansichtssteuerfunktionen, w ird
das Layout Ihrer Anwendung auf Funktionsebene einfach (siehe Abbildung 2-4).
49
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Außerdem stellt der vollständige Framework-Entwurf sicher, dass die Steuerf unktionen in derselben Reihenfolge ausgeführt werden, wie sie den Befeh len zugeordnet sind. Im vorstehenden Zuordnungscode wird die Funktion checkNumbersVal CF immer vor der Funktion d i v i s i on By Zer oVa l CF aufgerufen.
ÄNWEN DUNGSCONTROLLE R
Ein Anwendungscontroller, der auf dem Standardmuster für Anwendungscontroller beruht, dient dazu, Befehle einer bestimmten Funktiona lität zuzuordnen. Daher bestehen Implementierungen des Musters im Allgemeinen aus einer Zuordnung, deren Sch lüssel Befehle und deren Werte Funktionalitätsziele sind.
Nach dem Entwurf in diesem Kapitel sind die mit den Sch lüsseln der Zuordnung verknüpften Werte Funktionslisten, was dem Controller ermöglicht, mehrere Funktionen in der angegebenen Reihenfolge auszuführen und die Modularität und Wiederverwendbarkeit der Steuerfunktionsziele zu erhöhen.
Ein gut gestalteter Anwendungscontroller macht Ihre Anwendung erweiterbar, wei l Sie Funktionalität hinzufügen können, ohne die Kommunikation der Funktionen untereinander neu schreiben zu müssen.
Die QuickConnectiPhone-lmplementierung eines Anwendungscontrollers ist ein Beil spiel dafür.
Nachdem Sie nun gesehen haben, wie die Befehle den Steuerfunktionen zugeordnet sind, können Sie sich dem Erstellen solcher Funktionen zuwenden. Die Funktion checkN um
be r s Va l CF ist recht typisch f ür Validierungssteuerfunktionen. Sie ist auf eine Einzelaufgabe ausgericht et und sorgt ausschließlich dafür, dass die vom Benutzer eingegebenen Werte numerisch sind. Andernfalls ruft sie einen der Anwendungscontroller, nämlich d i spatchToECF, auf, um den Fehler zu behandeln:
f unct ion checkNumber sVa l CF(paramet er s){ //überprüfen , ob a und b Zahl en si nd
so
var a = document .get El ementßyld( ' a ' ) . val ue ; var b = document .get El ementßyld( ' b ' ) . val ue ; if (isNaN( a) I I isNaN( b)){
di spatchToECF( ' badNum', ' Ent er numbers on l y . ' ) ; r et ur n fa l se ;
return true ;
Das JavaScript-Framework von QuickConnectiPhone
Validierungssteuerfunktionen geben t rue zurück, wenn die Situation als korrekt ausge
wertet wird, sonst f a 1 se. Dadurch ist es möglich, die Verarbeitung bei einem Fehler sofort
anzuhalten, was die Sicherheit Ihrer Anwendung erhöht.
Weiter vorn in diesem Abschnitt hat die Unternehmenssteuerfunktion ca 1 cu1 ate
So1utionBCF solche Funktionen dem Befehl math zugeordnet. Wie die meisten Unter
nehmenssteuerfunktionen fragt sie Daten ab, um damit zu arbeiten. ln diesem Fall holt sie die Daten aus der Benutzeroberfläche. ln anderen Fällen holt eine Unternehmens
steuerfunktion vielleicht Werte aus einer Datenbank oder mithilfe von AJAX von einem
Server im Internet. Der folgende Code enthält die Implementierung dieser Unterneh
menssteuerfunktion:
function ca1cu1ateSo1uti onBCF(parameters ){ var a document. getE1ementßy l d( 1 a 1 ).va1ue; var b = document. getE1ementßy l d( 1 b 1 ).va1ue;
if( a = I I ){
a = 0 ;
if(b = I I ){
b = 0 ;
//Ergebni s der Berechnung auswerten var expression = a+parameters[O]+b; var resu1t = eva 1(expression); return new Array(a , b, resu1t);
Unternehmenssteuerfunktionen geben nicht w ie Val idierungssteuerfunktionen einen
booleschen Wert, sondern ein Array mit Daten zurück. Es kann beliebige Informationen
enthalten. ln diesem Fa ll werden die beiden vom Benutzer eingegebenen Werte und das
berechnete Ergebnis zurückgegeben, wei l alldies später benötigt w ird, um die Anzeige für
den Benutzer zu erstellen (siehe Abbildung 2.2).
Die eigentliche Berechnung des Ergebnisses erfolgt mit der JavaScript -Funktion eva 1,
die versucht, einen beliebigen String so auszuf ühren, als enthielte er gültigen JavaScript
Code. Gibt der Benutzer in diesem Fa ll als Werte 3 und 5 ein und betätigt die Schaltfläche
Mu 1 t i p 1 y, enthält die Va riable express i onden String »3*5«. Wenn dieser an ev a 1 über
geben wi rd, lautet das zurückgegebene Resultat 15.
51
Kapitel2 JavaScript-Modularität und iPhone-Anwendungen
Seien Sie mit der Funktioneva l vorsichtig, weil sie jeden String ausführt, den sie bekommt.
ln der Beispielanwendung s i mp l eCa l c ist sie gefahrlos verwendbar, weil die Validie
rungssteuerfunktion durchlaufen wurde, die dafür sorgt, dass die Werte a und b Zahlen
sind. Ist bei den Elementen, die im Aufruf von ev a l verwendet werden, keine Validierung
durchgeführt worden, könnten Benutzer die Funktionsweise einer Anwendung erkennen
und Schaden anrichten, beispielsweise mit einem SQL-Einfügeangriff, wenn die Unter
nehmenssteuerfunktion Datenbankzugriff besitzt.
Die Funktion d i s p l ay So l ut i on V CF ist ein einfaches Beispiel für Ansichtssteuerfunk
tionen. Wie die anderen Steuerfunktionen erledigt sie genau eine Sache: Sie aktualisiert
das d i V-Element f ür die Anzeige mit einem String, der die durchgeführte arithmetische
Operation und das berechnete Ergebnis zeigt:
function di sp l ay Sol utionVCF Cdata, pa r ameters ){ var resu l t = data[OJ [O J+' '+parameters [ OJ
+ ' '+data[O J[ l]+' = '+data [0 ] [2 ] ; document.getE l ementBy l d( ' di spl ay ' ) . i nnerHTML result;
Im Allgemeinen aktualisieren Ansichtssteuerfunktionen den HTML-Code der Hauptseite
in irgendeiner Weise. Ein Beispiel für eine größere Änderung der Ansicht ist das Ausblenden der gesamten sichtbaren Benutzeroberfläche. Dieses Beispiel nimmt nur eine kleine
Änderung vor. Es zeigt die durchgeführte Rechnung und lässt den Rest der Benutzeroberfläche unberührt.
Auch Feh lersteuerfunktionen können einfach oder komplex sein. Sie können Verhalten
wie das Ändern gespeicherter Daten umfassen oder so einfach ausfallen wie das folgende
Beispiel für ent ry EC F. Es übernimmt als einzigen Parameter einen String und zeigt ihn
dem Benutzer an:
function entry ECFCmessage ) { document.getEl ementBy l d( ' di spl ay ' ) . i nnerHTML = message;
Wegen ihrer Einfachheit kann diese Feh lersteuerfunktion beim Scheitern derValidierung
in beiden Va lidierungssteuerfunktionen dieser Beispielanwendung eingesetzt werden.
Mit einer guten Implementierung des Front- bzw. Anwendungscontrollers können Sie
Entwurf und Umsetzung der Anwendung auf das eigentliche gewünschte Verha lten kon
zentrieren anstattauf Kommunikation und Datenübergabe zwischen den Funktionen. Im
nächsten Abschnitt sehen Sie eine Implementierung eines Frontcontrollers und mehrerer
Anwend u n gscontroller.
52
Die QuickConnectiPhone-Umsetzung des modularen Entwerfens
2.3 DIE QUICK(ONNECTIPHONE-UMSETZUNG DES
MODULAREN ENTWERFENS
Wie die meisten anderen Tei le der Entwurfsumsetzung in diesem Abschnitt ist auch die
Funktion handl eRequest kurz und knapp. Sie und die Methode, deren Fassade sie dar
stellt, bestehen aus 21 Codezeilen, von denen nur 15 aktiv sind. Im folgenden Code sind die
interessanten Zeilen 7 bis 21 fett gedruckt.
Da die Funktion handl eRequest die Implementierung des Frontcontrollers des im
vorigen Abschnitt behandelten Entwurfs darstellt, ist sie für den Aufruf von vier Anwen
dungscontrollern zuständig. Jedem davon obliegt die Behandlung eines Steuerfunktions
typs. Als erster Anwendungscontroller wird d i spatchToVa l CF aufgerufen (Zeile 7 des
folgenden Codes). (Die einzelnen Anwendungscontroller-Funktionen werden in Tabelle 2.3 beschrieben.)
M ethodensignatur Rückgabe Parameter
dispa tc hToVa l CF Ein boaleseher Wert. a Cmd- ein eindeut igerString mit
( aCmd, pa ramArray) Bei Erfolgt r ue, bei dem zu verarbeitenden Verhalten,
Feh lschlag fa l se. zum Beispiel d i sp l ayßl ogEntri es
pa ramAr ray- ein optionaler
Parameter, der aus einem Array
von Variablen besteht, die bei der
Verarbeitung benötigt werden
dispa tc hToBCF(aCmd, Anzeigefert ige Daten a Cmd- ein eindeut igerString mit pa ramArray, oder stop. Wi rd dem zu verarbeitenden Verhalten,
ca l l ßac kData ) stop zurückgegeben, zum Beispiel d i sp l ayßl ogEntri es
erfolgt keine weitere pa ramAr ray- ein optionaler
Berechnung für den Parameter, der aus einem Array
angegebenen Befehl. von Variablen besteht, die bei der
Verarbeitung benötigt werden
ca l l BackDa ta- ein optiona ler
Parameter, den das Framewerk
erstellt, wenn asynchrone Aufrufe
aus Unternehmenssteuer-
funktionen erfolgen, die mit dem
Befehl verknüpft sind
53
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
dispatchToVCF(aCmd , vo i d aCmd- ein eindeutigerString mit
data, paramArray, ) dem zu verarbeitenden Verhalten,
zum Beispiel d i spl ayß l og Entr i es
data- ein Array mit sämtlichen Daten, die Aufrufe von Unter-
nehmenssteuerfunktionen erzeugen
pa ramArray- ein optiona ler
Parameter, der aus einem Array
von Variablen besteht, die bei der
Verarbeitung benötigt werden
d ispa t chToECF(aCmd , void aCmd- ein eindeutigerString mit
errorMessage) dem zu vera rbeitenden Verhalten,
zum Beispiel d i sp l ayß l og Entri es
errorMessage -eine Meldung,
die den Entwickler mithilfe von
Protokollen oder den Benutzer
mithilfe der Anzeige informiert. Sie
sol lte aussagekräftig und f ür den
Zielbenutzer hilf reich sein, f ür den
sie gedacht ist.
Tabelle 23: Die Anwendungscontroller-API
Die Funktion dis pa tchToVa l CF ruft sämtliche Validierungssteuerfunktionen auf, die Sie
dem Wert command in der Variablen aCmd zugeordnet haben. Wird die Validierungsfunk
tion aufgerufen, gibt sie den booleschen Wert t r ue zurück, wenn eine feh lsch lägt dage
genfa l se.
Da der Aufruf vond is pa tc hToVa l CF von einer i f -Anweisung umschlossen ist, w ird Ihre
Anforderung nur bei Rückgabe von t rue weiter verarbeitet. Andernfa lls fä llt sie, fa lls Sie
dem Hauptbefeh l Feh lersteuerfunktionen zugeordnet haben, in der Fehlerbehandlungs
routine durch. Die bereits vorgestel lte Beispielanwendung s i mp l eCa l c weist jedoch
keine derartigen Zuordnungen auf.
54
Die QuickConnectiPhone-Umsetzung des modularen Entwerfens
1 f unction handl eRequest(aCmd, pa ramArray){ 2 requestHa ndl er (aCmd, par amArray, nul l ) ; 3 4 5 f unction reques tHandl er(aCmd, paramAr r ay , call BackData ){ 6 i f ( aCmd !=nul l){ 7 8 9 10 11 12 13 14 15 16 17 18 19 el se{
i f ( di spatchToVal CF( aCmd, paramArray)){ t ry{
var data = dispatchToBCF( aCmd, pa r amArr ay , ca llBackData ) ;
if( da t a != ' stop' ) { dispatchToVC F(aCmd , data , paramArray) ;
catch(err ){ l ogError(e r r) ;
20 di spatchToECF ( aCmd, ' va lidati on fa i l ed ' ) ; 21 22 23
Nachdem Ihre Anforderung die Validierung durchlaufen hat, ruft das Frontcontroller
modul den nächsten Anwendungscontroller auf, d i spa t chToBCF. Diese Funktion ruft
die Unternehmenssteuerfunktionen auf, die Sie mit dem Befehl verknüpft haben, um die
gewünschten Dat en abzurufen oder zu speichern.
Gibt Ihre Unternehmenssteuerfunktion etwas anderes zurück als s top, ruft der Frontcont
roller die Ansichtssteuerfunkt ionen auf, die Sie außerdem mit dem Befehl verknüpft haben.
Dazu benutzt sie den dritten Anwendungscontroller, di spatchToVCF. Weitere Informat io
nen über Unternehmens- und Ansichtssteuerfunktionen finden Sie in Abschn itt 4·
Der Zweck des erwähnten Frontcontrol ler-Moduls besteht darin, eine schnel le und einfa
che Möglichkeit bereitzustellen, um f ür einen stabi len, sicheren Berechnungsfluss durch
Ihre Anwendung zu sorgen. Wird ein Vera rbeitungsfluss ständ ig genutzt, ist es wesentlich
einfacher, Ihre Anwendungen zu erstellen und Fehler darin zu beheben. Verwenden Sie
die QuickConnectiPhone-lmplementierungen des Entwurfs, sollt en Sie daher die Funktion
hand l eRequest aufrufen, wenn Sie wollen, dass in der Anwendung etwas geschieht.
55
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Jede Anwendungssteuerfunktion aus Tabel le 2.3 spielt eine andere Rol le und ermöglicht
die Handhabung Ihres Befehls zur Fortsetzung oder Unterbrechung in Abhängigkeit von
Ihren Entscheidungen in den Valid ierungs- und Unternehmenssteuerfunktionen. Es han
delt sich dabei um Module, weil sie wiederverwendbar, lose gekoppelt und eng zusam
menhängend sind.
Die Funktion d i s pa tchToVa l CF stellt eine Fassade dar. Diese Funktion und die Funktion
di spatchToSC F sind identisch, was ihr Verhalten angeht, bearbeiten aber unterschied
liche Datenmengen. Mit Validierungssteuerfunktionen untersuchen Sie Benutzereingaben.
Sicherheitssteuerfunktionen (Security Control Functions, SCFs) sollen dagegen sicherstellen,
dass Daten aus entfernten Quellen wie Websites keinen Schadcode ent halten. Aufgrund
dieser Funktionsähnlichkeit legen Sie den Arbeitscode am besten zentral ab und setzen zum
Aufrufen der zugrunde liegenden Prüffunktion Fassadenfunktionen ein.
Der folgende Code aus der Datei Ou i ckConnect. j s zeigt die Fassadenfunktion
d i spatchToVa l CF und die ihr zugrunde liegende Funktion check. Wie Sie sehen, ruft
d i spa t chToVal CF die Prüffunkt ion auf und übergibt dieser ihre beiden eigenen Para
meter sowie einen weiteren. Dabei handelt es sich um einen String, der beschreibt, welche
Art von Zuordnungstabelle die Funkt ion verwenden sol l. Diese Zuordnungstabelle, ein
assoziatives Array, enthält sämtliche Verknüpfungen zwischen Befehlen und einem Array
von Validierungssteuerfunktionen. Wie Sie Befehle erstel len und mit Va lid ierungssteuer
funktionen verknüpfen, steht in Abschnitt 2 dieses Kapitels.
1 function dispatchToVa l CF(vali dat ionCommand , paramArray){ 2 return check(va l i dationCommand , ' va li dation ' , paramArray ) ; 3 4
5 /* 6 *Diese Funkt ion soll nicht direkt vom Programmierer aufgeru fen
* werden . Verwenden Sie sie nicht. 7 */ 8 function check(command, t ype , data){ 9 var retVa l = t rue ;
10 /* 11 * all e Standardfunktionen ausführen , die für al l e
* Be fehle gel t en, wenn Standardfunktionen definiert sind 12 */
56
Die QuickConnectiPhone-Umsetzung des modularen Entwerfens
13 var map = securityMap; 14 if(type = 'va l ida t ion'){ 15 map = va l ida t ionMap; 16 17 var defaultFuncs = map['default'J: 18 if(defaul t Funcs){ 19 var numFuncs = defaultFuncs.length: 20 for(var i = 0; i < numFuncs; i++ ){ 21 retVa l = defaul t Funcs[i] (command , data ) ; 22 if(retVal = fa l se){ 23 break: 24 25 26 27 /* 28 * wenn die Standardfunktionen passiert haben,
*die befehl sspezifisc hen ausführen 29 */ 30 if(retVa l = true){ 31 command Funcs = map [command]; 32 33 34
35 36 37 38 39 40 41 42 43 44
i f (commandFuncs){ var numFuncs commandFuncs . l ength; for (va r i = 0: i < numFuncs; i++){
retVa l = commandFuncs [ i]( data); if(re tVa l == fa l se){
brea k:
return retVal :
ln Zeile 17 versucht der Code, ein Array mit Steuerfunktionen abzurufen, die mit dem Befehl defau l t verknüpft sind. Das Abrufen dieser Funktionen bedeutet, dass Sie eine Ansichtssteuerfunktion schreiben kön nen, die für jeden Befehl aufgerufen wird, den Sie an handl eRequest senden, wenn Sie siedefaul t zuordnen.
57
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Eine gängige Standardvalidierungssteuerfunktion ist eine, die dafür sorgt, dass in der
Zuordnungstabel le für die Unternehmens- oder die Ansichtssteuerfunktionen oder in
beiden eine Zuordnung für den Befehl vorhanden ist, der gerade übergeben wird. Feh lt der
Befehl in diesen Funktionen, gibt es keinen Grund, mit seiner Verarbeitung fortzufahren,
wesha lb die weitere Prüfung abgebrochen und fa 1 se zurückgegeben wird.
Indem die Funktion f a 1 se zurückgibt, veranlasst sie die Funktion d i spa tc hToVa l CF, sofort dasselbe zu tun. Dies veran lasst wiederum den Frontcontroller, die weitere Verarbei
tung zu beenden. Diese Validierungssteuerfunktion fängt nicht zugeordnete fehlerhafte
Befehle ab, bevor sie im weiteren Verlauf zu Problemen in Ihrer Anwendung führen.
Gibt es keine Standardvalid ierungssteuerfunktionen oder durchläuft der Befehl alle mit
dem Befehl defa ul t verknüpften, ruft die Methodecheck ansch ließend die Liste der mit
dem betreffenden Befehl verknüpften Validierungssteuerfunktionen ab und führt sie der
Reihe nach aus.
Diese vorherige Prüfung von Eingaben al ler Art stellt, wie in Abschnitt 2 erörtert wird,
einen Zweck der Funktion d i s pa tchT oVa 1 CF und der von Ihnen erstellten Va lidierungs
steuerfunktionen dar. Außerdem ermöglicht sie Ihnen, den Va lidierungs- und den Ausfüh
rungscode zu t rennen, was den Support Ihrer Anwendung erleichtert. Es hilft Ihnen auch beim Schreiben der Software, indem es das Entwerfen vereinfacht (siehe Abschnitt 2).
2.4 IMPLEMENTIERUNG VON UNTERNEHMENS- UND
ANSICHTSANWENDUNGSCONTROLLERN
Der Unternehmensanwendungscontrol ler ist der komplexere der beiden Anwendungs
controller, der Ansichtsanwendungscontroller ist dagegen einfach. Die Funktion di s
patchToBCF ruft al le einem Befehl zugeordneten Unternehmenssteuerfunktionen auf, auch wenn eine oder mehrere davon asynchrone Aufrufe vornehmen. Die Funktiond is
pa tchToVC F ist wesentlich einfacher, weil sie der Funktiond is pa tc hT oVa 1 CF sehr stark
ähnelt und Ansichtssteuerfunktionen niemals asynchron sind. Obwohl sich beide Funk
tionen ähnlich verhalten, unterscheidet sich ihre Umsetzung erheblich.
Wie in Abschnitt 2 erörtert, wird die Unternehmensanwendungssteuerfunktion nur aufgerufen, wenn die von Ihnen definierten und zugeordneten Va lid ierungssteuerfunktionen
ergeben, dass die Verarbeitung gefahrlos fortgesetzt werden kann. Obwohl die Funktion
zum Teil dieselben Ideen benutzt wie die Methode chec kVa 1 i da t i on, unterscheidet sie
sich erheblich von dieser.
Die Funkt ion di spatc hToBC F besteht aus zwei Haupttei len. Der erste umfasst Zeile 18 bis 40 und befasst sich mit dem Array ca 11 Ba ckData, das die bei einem asynchronen
Aufruf gesammelten Daten enthält. Nimmt Ihre Unternehmenssteuerfunktion keine
asynchronen Aufrufe vor, ist das Array nu l l . Führt sie einen Aufruf aus, beispielsweise
58
Implementierung von Unternehmens- und Ansichtsanwendungscontrollern
einen AJAX-Aufruf oder einen Aufruf zum Abfragen von Daten aus einer Datenbank, ent
hält das Array die Daten, die erforderlich sind, um die übrigen dem Befehl zugeordneten
Unternehmenssteuerfunktionen aufzurufen. ln Zeile 25 und 31 sehen Sie, dass das Array
ca ll Ba c kDa t a die Ergebnisse aller vor dem asynchronen Aufruf aufgerufenen Unter
nehmenssteuerfunktionen sowie die von diesem selbst erzeugten Daten enthält.
J DEFIN ITION VON »ASYNCHRON «
Bei der Arbeit mit Computern denken Sie gewöhnlich synchron, d.h., Sie tun Dinge
einzeln in einer definierten Reihenfolge. Beim Aufrufen einer Funktion erwarten Sie
normalerweise, dass die einzelnen Schritte nacheinander ausgeführt werden. Sind alle
Schritte erledigt, gibt die Funktion einen Wert oder voi d zurück.
Asynchrones Verhalten unterscheidet sich davon. Es ähnelt eher einem Fußballspiel.
Im Spiel ist jeder damit beschäftigt, ohne Rücksicht darauf, ob jemand anders auch
damit beschäftigt ist, das Notwendige zu tun. Alles andere wäre dumm. Stellen Sie sich
ein Spiel vor, in dem alle Spieler darauf warten, dass andere mit dem fertig werden,
was sie getan haben, bevor sie selbst anfangen, sich zu bewegen. Einfach dumm.
Asynchrones Verhalten in der Datenverarbeitung bedeutet, dass Sie eine Funktion an
weisen können, etwas zu tun, während die Verarbeitung fortgesetzt wird, ohne darauf
zu warten, dass die Funktion etwas zurückgibt.
Zei le 34 f ügt in den Fällen, in denen vorher keine Unternehmenssteuerfunktion aufgeru
fen w urde, die vom asynchronen Aufruf erzeugten Daten in das Array resul ts ein. Das
Array sieht nach Ausführung der Zei le daher fü r den Rest des Codes so aus, als hätten
keine asynchronen Aufrufe stattgefunden.
Zeile 37 fragt die Indexnummer der Unternehmenssteuerfunktion ab, die den asynchronen
Aufruf getätigt hat; andernfalls wüsste der Rest der Funktion di spatchToBCF nicht, wie
viele dem Befeh l zugeordnete Unternehmenssteuerfunktionen bereits ausgeführt wurden.
Asynchrone Aufrufe stellen einen »Bruch« in der Ausführung der dem Befehl zugeordneten
Unternehmenssteuerfunkt ionen dar. Die Funktion d i spa t chToBC F weiß nur dann, welche
Unternehmenssteuerfunkt ionen bereits ausgeführt wurden, wenn in den Daten, die sie aus
den Ergebnissen des asynchronen Aufrufs erhält, ein Hinweis enthalten ist.
ln Kapitel 6, »Datenbankzugriff«, geschieht dies mithilfe der Methoden getDa t a, set
Da ta, getNativeData und setNativeData des Da taAccessObject. Wenn Sie ein
eigenes Framewerk erstellen, das asynchrone Aufrufe ermöglicht, sollten Sie Code wie den
folgenden vorsehen:
59
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
1 function dispatchToBCF(aCmd, paramArray, callßackData ){ 2 3 if(event = null) { 4 event = window . event: 5 6 if(event != null) { 7 stopDefaul t (event); 8 9 wi ndow.curCmd = aCmd: 10 if(paramArray){ 11 window .globalParamArray paramArray; 12 13 else{ 14 15
window .gl oba l ParamArray new Array();
16 var resu l ts = new Array() ; 17 window .numFuncsCal l ed = 0: 18 if(ca l l ßackDa t a){ 19 if(ca ll ßackDat a[OJ){ 20 if(cal l ßack0ata [1 ] ){ 21 var accumula tedData FromCa l l back =
22 ca l l ßack0ata[1 ][3J : 23 if(accumul atedDataFromCa l l back && 24 accumul atedDataFromCa ll back . l engt h > 0){ 25 resu l ts = accumulatedData FromCa l l back ; 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
if(resul ts . l ength = 0){ // resu l ts sol l immer ei n Array sein. // Die Kl ammern [ ] sorgen dafür. resu l ts = [ca l l ßackData[O JJ :
el se{ resu l ts. pus h(cal l ßackDa ta [O]);
if(ca ll ßack0at a[1]){ window . numFuncsCa l l ed ca l l ßack0ata[1 ][1];
41 var stop = fa l se; 42 i f(aCmd) {
60
Implementierung von Unternehmens- und Ansichtsanwendungscontrollern
43 44 45 46 47 48 49 50
var commandlist = businessMap[aCmd]; call Func = function(data){
if( data) { resul t s.append(data); window .globa l BCFResul ts = resu l ts;
i f (window . num FuncsCa l l ed < commandlist . l ength){ var funcToCa l l =
51 52
commandl i st [wi ndow . numFuncsCa ll ed ] ; window.numFuncsCal l ed++;
53 54 55 56 57 58 59 60 61 62 63 64 65
66 67 el se{
var resu lt = null; t ry{
resu l t = funcToCa l l (paramArray , resul t s) ;
catch(err){ di spatchToECF( ' runFa i l ure '.
err .message) ;
if(result != null ){ resu l ts[resul ts . l ength] ca l l Func() ;
result ;
68 stop = true ; 69 70 71 72 73 74 75
if(commandli st && command l ist . l engt h > 0){ ca ll Func() ;
76 if( stop ){ 77 ret urn ' stop '; 78 79 re t urn resu l ts ; 80
61
Kapitel2 JavaScript-Modularität und iPhone-Anwendungen
Die Zeilen 41 bis 8o der Anwendungssteuerfunktion di spatchToBCF enthalten drei Tätig
keiten:
> Erstellung und Verwendung anonymer JavaScript-Funktionen
> Rekursion in JavaScript
> Auf rufen der mit einem Befehl verknüpften Unternehmenssteuerfunktionen
Anonym ist jede Funktion, die »nebenbei« innerhalb einer anderen Funktion angelegt
w ird, beispielsweise die Funktion ca ll Func in Zeile 44 bis 71 des vorstehenden Codes.
Außerhalb der Funktion d i spa tc hToBCF kommt diese Funktion nicht vor. Wie alle anony
men Funktionen ist sie streng auf den Gültigkeitsbereich der Funktion beschränkt, inner
halb derer sie deklariert wird. Al le Variablen, die in der umschl ießenden Funktion vor der
anonymen Funktion deklariert wurden, liegen trotzdem innerhalb des Gültigkeitsbereichs
und können in der anonymen Funktion benutzt werden, obwohl sie nicht als Parameter
übergeben wurden.
Zeile 43 und 44 bilden ein Beispiel dafür. Die Variable commandl i st wi rd außerha lb der Funktion ca l l Func definiert, nicht an diese übergeben und t rotzdem innerhalb der Funk
tion verwendet. ln Zeile so und 51 wird sie benutzt, um die nächste auszuführende Unter
nehmenssteuerfunktion aufzurufen. in Zei le 55 und 56 wird die Steuerfunktion ausgeführt,
und die Ergebnisse werden gespeichert.
Als Beispiel fü r Rekursion ruft sich ca l l Func in Zei le 65 selbst auf Dies geschieht am
Ende der Funktion und nur dann, wenn das Ergebnis des Aufrufs der Steuerfunktion nicht
nul l ist. Diese Art von Rekursion wird als Endrekursion bezeichnet, weil die Prüfung
am Sch luss der Funktion liegt. Findet sie am Anfang der Funktion statt, spricht man von
Anfangsrekursion. Die vollständige Rekursionskaskade, die die Funktion ca l l Func aus
löst, beginnt mit dem Aufruf in Zeile 73-
REKURSION
Rekursion ist der Aufruf einer Funktion durch sich selbst.
Wenn die Funktion di spatchToVCF aufgerufen wird, ruft sie, wie Sie im folgenden Code
sehen, eine Liste von Steuerfunktionen ab, die dem Befehl zugeordnet sind Im Unterschied
zur Validierungsanwendungssteuerfunktion wird ihr ein Datenparameter übergeben: ein
Array, das die einzelnen Ergebnisse der Aufrufe der Unternehmenssteuerfunktionen enthä lt.
62
Die Implementierung des Fehleranwendungscontrollers
Gibt eine der Ansichtssteuerfunktionen stop zurück, werden wie bei di spatchToBCF keine weiteren Va lidierungssteuerfunktionen ausgeführt. Daher kann der Programmierer die weitere Ausführung beenden, indem er die Funktion di spatchToECF aufruft.
function dispatchToVCF(aCmd, data, paramArray){ if( aCmd) {
var vcfFunc l ist = viewMap [ aCmd]: if ( vcfFunc List = null ) {
vcfFunclist = new Array() ;
var numFuncs = vcfFunclist.length: for(var i = 0 : i < numFuncs ; i ++){
try{ retVa l = vcfFunclist [ i ] (da ta, paramArray) ;
catch(err) { debug(errorMessage(er r )) ;
i f(retVa l && retVa l = 'stop ' ) { break:
Die einzelnen Va lidierungssteuerfunktionen werden aufgerufen und ihnen die Ergebnis
daten der Unternehmenssteuerf unktion sowie die ursprünglichen Parameter in Form der Variablen pa ramAr ray übergeben, die Ihre Anwendung an die Funktion ha nd l eReques t gesendet hat . Dies wurde in die Implementierung aufgenommen, um Ihnen die Möglichkeit zu geben, den vom Unternehmens- und vom Ansichtsanwendungscontroller aufgerufenen Unternehmens- und Ansichtssteuerfunktionen Informationen zu übermitteln.
2.5 DIE IMPLEMENTIERUNG DES FEHLERANWENDUNGS
CONTROLLERS
Anders als bei den anderen in Abschnitt 3 und 4 behandelten Anwendungscontrollern ermöglicht die Implementierung des Fehleranwendungscontrollers im QuickConnectiPhone-Framework nur die Zuordnung einer einzigen Fehlersteuerfunktion zu einem Befeh l. Jede Fehlersteuerfunkt ion muss den Fehler also vol lständig behandeln, was die
Änderung gespeicherter Daten, die Aktualisierung der Ansicht zwecks Information des Benutzers und anderes umfasst.
63
Kapitel 2 JavaScript-Modularität und iPhone-Anwendungen
Der folgende Code implementiert einen einfachen Fehleranwendungscontroller:
f unct i on dispatchToECFCer rorCommand , errorMessage){ var err orFunc = errorMap[error Command]; if(errorFunc){
r et urn errorFunc(errorMess age) ;
Diese Implementierung ruft einfach die auszuführende Fehlersteuerf unktion ab und
übergibt ihr die Feh lermeldung. Um die Fehlerbehandlung auf diese Weise zu akt ivieren,
istein direkt er Auf ruf von d i spa t chToEC F erforderlich, anstatt über hand l eRequest zu
gehen. ln der Funktion chec kNumbe r s Val CF finden Sie folgende Codezeile:
dispatchToECFC 'badNum ' , ' Enter numbers on l y . ' ) ;
Dieser Auf ruf von d i spa t chToEC F übergibt eine Meldung, die in die Anzeige der Benutzeroberfläche aufgenommen werden soll und dem Benutzer mitteilt, dass nur Zahlen als
Eingabewert e akzept iert werden.
2.6 DIE FUNKTIONALITÄT DER ANWENDUNG ERSTELLEN
ln Abschnitt 3 bis 5 w ird erläut ert, was hint er den Kulissen geschieht, wenn Sie die Im
plementierung des Front - und Anwendungscontrollerentwurfs des QuickConnect iPhone
Frameworks benutzen. Welche Schritte müssen Sie f ür die Erstellung des Großtei ls der
Anwendungsfunktionalität nacheinander unternehmen?
1. Sämtliche Unternehmenssteuerfunktionen zum Abrufen oder Speichern von Daten
schreiben (siehe Abschnitt 4)
2. Sämtliche Ansichtssteuerfunktionen zum Ändern der Benutzeroberfläche schreiben
(siehe Abschnitt 4)
3. Sämtliche für die Benutzereingaben erforderlichen Validierungssteuerfunktionen
schreiben (siehe Abschnitt 3)
4. Sämtliche zur Behandlung möglicher Fehlerbedingungen erforderlichen Fehler
steuerfunktionen schreiben (siehe Abschnitts)
5. Alle neuen Steuerfunktionen mithilfe der passenden mapCommandTo***-Funktion
einem Befehl zuordnen
Wenn Sie diese f ünf Schritte erledigt haben, ist die neue Funktionalität Bestandt eilihrer
Anwendung.
64
Zusammenfassung
2.7 ZUSAMMENFASSUNG
Modularität macht Ihren Code einfacher erstellbar, leichter pflegbar und kleiner, wenn
sie richtig angewandt wird. Wenn Sie dies und die Geschwindigkeit der Ausführungsziele
vor Augen haben, erleichtert die Implementierung des QuickConnectiPhone-Frameworks,
die Ihnen in j eder Anwendung zur Verfügung gestel lt wird, die Sie mit den QuickConnec
tiPhone-Anwendungsvorlagen erstellen, Ihnen das Leben erhebl ich. Sie können sich auf
das konzentrieren, was Sie wollen, nämlich Funktionalität für Ihre Benutzer schreiben und
bereitstellen. Die Kommunikation zwischen den Funktionen und die Steuerung der Funk
tionen erledigt das Framewerk für Sie.
Mit der Erstellung von Validierungs-, Unternehmens-, Ansichts- und Fehlersteuerfunktio
nen können Sie den Umfang Ihrer Arbeit problemlos so gestalten, dass die Produktivität
zunimmt, während Sie gleichzeitig Qua lität und Sicherheit Ihres Codes steigern.
65
Benutzerschnittstellen für das iPhone erstellen
Das iPhone bietet einzigart ige Methoden fü r die Interaktion mit dem Benutzer. Bei diesem
neuen Medium reichen ältere Methoden zum Entwerfen von Schnittstellen nicht aus. Eine
von Ihnen erstellte Anwendung kann dem Benutzer die intuitiven Schnittstellen interaktio
nen und -elementezur Verfügung stellen, nach denen iPhone-Benutzerverlangen.ln diesem
Kapitel geht es darum, wie das zu erreichen ist. Außerdem werden die Schnittstellenricht
linien von Apple erörtert, mit deren Hilfe Anwendungen bewertet werden können, die in
den App Store aufgenommen werden sollen. Des Weiteren w ird ein Modul f ür Drag&Drop,
Skalierung und Drehung gezeigt und erläutert, damit Sie sehen, wie Sie mit Berührungs
und Gestenereign issen in JavaScript umgehen. Diese neuen JavaScript-Ereignistypen sind
nämlich fü r die Gesta lt ung der iPhone-Benutzerschnittstelle wesentlich.
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
3.1 DIE SCHNITTSTELLENRICHTLINIEN VON ÄPPLE
Um iPhone-Benutzern gleichartige Erlebnisse zu ermöglichen, hat Apple Richtlinien dafür
aufgestellt, was in iPhone-Benutzerschnittstellen verwendet werden soll. Dieser Abschnitt
stellt Ihnen die Grundlin ien und wichtigsten Punkte der Schnittstellenrichtlinien (Human
Interface Guide, HIG) des iPhones kurz und knapp vor. Die vollständigen Richtlinien finden
Sie unter folgender Adresse:
http:lldeveloper.apple.comliphone!library!documentation!UserExperience!Conceptual!
MobileH/C/Introductionllntroduction.html.
Die Schnittstellenrichtlinien für das iPhone beruhen auf den bereits früher für OS X und
die iPhone-Webentwicklung aufgestellten; vieles wurde daraus übernommen. Die neuen
Richtlinien stützen sich auf die Stärken ihrer Vorgänger und ergänzen sie durch Elemente, die spezifisch fü r iPhone-Anwendungen sind.
Der Platz des iPhone-Displays ist so begrenzt, dass Textausgaben fü r den Benutzer schnel l
unübersichtlich werden können. ln Anwendungen, deren Hauptfunktion nicht im Lesen
von Textdaten liegt, sollten nach Möglichkeit Bilder und Symbole verwendet werden, um
dem Benutzer Ideen und Funktionen nahezu bringen.
Der Schritt weg von Textsignalen gehört zum Wesen des iPhones. Es hat weder Pul I-down
Menüs noch Banner. Sie sol lten daher auch in Ihrer Anwendung darauf verzichten. Wenn
sie gut gestaltet ist, sollte sie intu itiv bedienbar sein. Andernfalls ist sie nicht für das iPho
ne geschrieben. Bei guter Gestaltung sol lte Ihre Anwendung ohne Gebrauchsanweisung
auskommen.
Ein Grund fü r das Ausufern von Pull-down-Menüs in vielen Anwendungen liegt darin,
dass sie nicht mehr einem einzigen Zweck dienen, sondern vielen. Betrachten Sie die ver
fügbaren Büroanwendungen, erkennen Sie leicht, wie sie sich von den einfachen, zweck
bestimmten Anwendungen, die sie einmal waren, zu den Giganten entwickelt haben, die
sie heute sind.
Textverarbeitungsprogramme verarbeiten nicht mehr nur Text. Sie müssen ausgefei lte
Layouts erstel len, Elemente aus vollkommen anderen Anwendungen einbinden können
und sogar eine Entwicklungsumgebung bereitstel len. Das Eindringen solcher Funktionen
hat diese Anwendungen zwar in gewisserWeise breit einsatzfäh ig, gleichzeitig aber auch
riesig und schwerfäl lig gemacht.
Jede iPhone-Anwendung sollte genau einen Zweck oder eine Funktion haben, die problemlos zu defin ieren und für den Benutzer leicht zu erkennen ist. Wenn Sie sich an den
Standard von Apple halten, ist Ihre Anwendung leichter verständ lich und füh rt zu ange
nehmeren Benutzererlebn issen.
68
Die Schnittstellenricht linien von Apple
Anwendungssteuerung ist eine wesentliche Komponente jedes Entwurfs. Ihre Anwen
dungen sol lten dem Benutzer möglichst viele Steuermöglichkeiten geben, d.h., sie sollten
kein bestimmtes Verhalten erzwingen. Die Beschränkung von Optionen wird in iPhone
Anwendungen nicht gern gesehen. Ein Beitrag dazu ist die flache Anordnung der Ansich
ten. Eine tiefe hierarchische Staffelung überlässt dem Computer die Verantwortung und
sollte vermieden werden.
Da Handbewegungen wie Berührung und Mehrfachberüh rung die Interaktionsmethoden
für das iPhone darstellen, sollte Ihre Anwendung dies unterstützen. Jeder Berührungs
punkt sollte eine angemessene Größe haben, damit der Benutzer ihn auswählen kann.
Der Standard sieht eine Höhe und Breite von 34 Pixel vor. Sind die Punkte kleiner, wei l Sie
versuchen, mehr Platz zu gewinnen, wi rd die Auswah l von Displayelementen für den Be
nutzer schwierig und sein Erlebnis unschön.
Die Verhaltensweisen Swipe und Pinch werden zwar unterstützt, sind aber möglicher
weise fü r den Benutzer schwer zu entdecken. Wol len Sie sie einbinden, sollten Sie optische
Hinweise darauf geben.ln einer E-Book-Anwendung können dazu zum Beispiel umgebo
gene Seitenecken angezeigt werden.
Von Drag&Drop-Funktionen raten die Schnittstellenrichtl inien im Allgemeinen ab, weil
diese üblicherweise fü r Bildlauf und Schwenks verwendet werden. Es lassen sich jedoch
leicht Beispiele für erfolgreiche Anwendungen m it Drag&Drop finden. Apple hat sogar ein
übermäßig kompliziertes Beispiel dafür produziert, w ie dies in JavaScript zu erreichen ist.
Der zweite Tei l dieses Kapitels zeigt Ihnen, w ie Sie Schnittstellenelemente fü r Drag&Drop,
zum Skal ieren durch Pinching und zum Drehen sauber und einfach umsetzen.
Tabelle 3.1 listet al le unterst ützten Handbewegungen und das damit verknüpfte Standard
verhalten auf. Indem Sie sich an diese Definitionen halten, erleichtern Sie es den Benut
zern, Ihre Anwendung zu erlernen. Definieren Sie die Verhaltensweisen jedoch um, w ird es
für die Benutzer schwieriger.
Handbewegung Verhalten
ta p Auswahl eines Schnittstel lenelements
drag Bildlauf oder Schwenk zur weiteren
Betrachtung
f l i ck Schneller Bildlauf oder Schwenk. Dies muss
ein weiteres Verhalten umfassen, wenn die
Handbewegung abgeschlossen ist.
69
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
swi pe Aufdecken verborgener Komponenten,
beispielsweise Schaltflächen zum Löschen
von Zei len in der Tabellenansicht oder
zusätzliche Ansichten
double tap Zentrieren und dann hinein- oder
herauszoomen
expand i ng pinch ( pinch open ) Hineinzoomen
contracting pi nch ( pi nch close ) Herauszoomen
touch and hol d Vergrößerte Ansicht zeigen
Tabelle 3.1: Handbewegungen und Standardverhaltensweisen für das iPhone
Das iPhone ist gewiss ein erstaunliches Gerät, aber im Vergleich mit der Dateneingabe an
einer Standardtastatur kann das Eingeben von Text mühevoll und langsam sein. Achten
Sie darauf, dass Sie nach Möglichkeit nicht die direkte Eingabe, sondern die Auswahl von
Daten vorsehen. Bei Web-Apps springen Selektoren auf, sogenannte Picker, wenn der
Benutzer ein HTML-Options-Tag auswählt . Die Verwendung solcher Selektoren in Ihren
Anwendungen beschleunigt die Steuerung durch den Benutzer und reduziert frustrieren
de Erfah rungen. ln Kapitel 4, »GPS, Beschleunigungsmessung und andere systemeigene
Funktionen von QuickConnect«, erfahren Sie, w ie Sie standardmäßige Zeitpicker für Da
tum und Uhrzeit in Ihre Web-Apps einbinden.
Die Schnittstellenrichtlinien fü r iPhone-Standardanwendungen sehen vor, Kontrol lkästchen und Optionsschaltflächen zu vermeiden; stattdessen sollen Scha lter benutzt werden. Auf
jedem iPhone und iPod touchgibt es im Lieferzustand die Anwendung Sett i ngs, die in
großem Umfang mit Schaltern arbeitet. Abbildung 3-1 zeigt die Safari-Optionen, die sich da
mit ändern lassen. Für die Entwickler von Web-Apps stellt diese Vermeidung von Optionsschaltflächen und Kont rollkästchen ein Dilemma dar.
Die Dashcode-Anwendung, die zum Entwickeln der Benutzerschnittstel le für Web-Apps
verwendet wurde, weist kein Widget für Schalter auf; es lässt sich jedoch leicht erstel len.
Es besteht aus einem Kasten mit eingelassenem Rand mit zwei Textelementen, OFF und
ON, sowie einer Scha ltfläche.
M ith ilfe der Handbewegungsereignisse der Scha ltfläche können Sie sie veran lassen, nach
rechts bzw. links zu gleiten, sodass sich für den neuen Schalter zwei Zustände ergeben. Mit der Ca llback-Funktion onges tureend, die Sie fü r die Schaltfläche definieren, stellen
Sie fest, ob es sich um den Zustand ON oder OFF handelt, und speichern ihn. Abbi ldung
3-1 zeigt die Schalter, die dem Benutzer zur Verfügung stehen, um die Einstellungen der
Safari-Anwendung zu ändern. Gesta lten Sie Ihre Schalter genauso.
70
Listen- und browsergestützte Schnittstellen
Befolgen Sie diese grundlegenden Gestaltungsregeln, dann erfüllt Ihre Anwendung die
Anforderungen für die Verteilung im Apple Store und die Erwartungen der Benutzer an die
Funktionsweise Ihrer Anwendung. Die Verletzung dieser Konzepte setzt sie dagegen dem
Risiko aus, sowohl von Apple als auch von potenziellen Benutzern abgelehnt zu werden.
Gonoral
r Search Englno
Security
Google >]
~ Abbildung 3.1: Die Schalter in der Anwendung Settings für Safari
3.2 LISTEN- UND BROWSERGESTÜTZTE SCHNITTSTELLEN
Einer der grundlegenden Benutzerschnittstellentypen fü r iPhone-Anwendungen bewältigt
die Anordnung innerhalb der Schnittstelle mithilfe von Listen. Die Qu ickConnect-Beispiel
anwendung Hi story Exampl e gehört dazu. ln Dashcode lässt sich diese Schnittstelle auf
zwei versch iedene Arten erstellen. Am schnellsten geht es, wenn Sie das Element Browser
verwenden.
Es ist in der BibliothekEl emente zu finden und lässt sich di rekt in Ihre Anwendung ziehen,
wodurch ein Stapel unabhängiger Ansichten angelegt wird. Ansichten sind die Hauptanzeigeeinheit, mit der es Benutzer zu t un haben; sie werden häufig fa lsch als Bi ldschi rme
bezeichnet. Wenn einer Anwendung ein Browser - El ement hinzugefügt w ird, werden
zwei Standardansichten eingefügt, der Code zum Umschalten zwischen ihnen jedoch nicht. Außerdem bekommt sie automatisch einen Header mit einer Navigat ionsscha ltfläche. ln
Abbildung 3-2 sehen Sie Das hcode nach dem Hinzufügen des Elements Browser.
71
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Die automatisch in den Header eingefügte Schaltfläche braucht nicht geändert zu wer
den, weil das B r owse r- El ement den darin angezeigten Text durch den des Headers der
vorherigen Ansicht erset zt (fa lls es eine gibt). Ändern Sie beim Erstel len einer Anwendung nicht den Text der Schaltfläche, sondern den des Headers, damit er den Namen der An
wendung oder etwas anderes Passendes anzeigt.
@ I"\ I"\
~. II r::J. , AusfOIHetl P<lv~ Dar~td!u119
B ohneTirc.l
S tOt'ltent
Unbenannt
fJD Q S.IL"'E'M
lnfo•ma.tl011~11 &ibloltli!St S11<htrt -~· , ,, 1 !d;' , , , , ,, i.bb ' ' , • , , , 1.,•, ,, , , ,, , llbö' , , , ~, , , • • ,, Ii&', •, ,, , , LtSo' , , ,, •, • isül , , _ N
[3 'l:i' •·'-.,.""', -----c ~ P'rogo~mrn.ltlributc
§ Webd tp -Symbol
~A..sfUI'Ir~o& rteigt !>tr'l
Oberfläche gestatten
ßt>'~cgcn 5le Ob:lt~u: t)IJ) dc• &bliOCII~It. itl d~t'l A.fbt H.t:'Je(e!d l uno Jo"'C~rn s,e a1e GgttHC.h;);ften derObjette •n den l11form~tioncn.
81tiiiOttltk. Ar'ooitsbereich klfcwmaliOilen
<..._ Ha neUer & Code ... ~
\. Attribute festlegen
\ Webd i p- Symbol entwerfen
\. TUltn & Ffeigeben
o· "' e s
~~
-:-o
DeveiOped V<th Oas!CO<le
~ Abbildung 3.2: Eine Dashcode-Anwendung nach dem Hinzufügen des Parts Browser
Beim Hinzufügen des Browser - El ements zu einer Anwendung werden zwei benannte
Standardansichten in das Projekt eingefügt. Nachdem Sie eine dieser Ansichten im Pro
jektbaum von Dashcode ausgewählt haben, sehen Sie die j ewei ligen Eigenschaften auf
der ersten roten Registerkarte des Informationsdialogs und können sie umbenennen. Ab
bi ldung 3-3 zeigt die Beispielanwendung Hi stor y, nachdem die Ansichten in ma i nV i ew und pres i dents Vi ew um benannt wurden. Beachten Sie die Optionen + und - für die Liste
subv i ews innerhal b des Infor ma t ionsfenst er s nach Auswa hl von St ackl ayou t
im Projektbaum. M it diesen Schaltflächen können Sie weitere Ansichten hinzufügen und
nicht benötigte entfernen.
72
Listen- und browsergestützte Schnittstellen
Sämtliche Ansichten in der Anwendung werden in der Liste Subvi ews verwaltet. Beach
ten Sie, dass sämtl iche Ansichten direkte Abkömmlinge des Stapellayouts sind, obwohl
die Navigation der Anwendung ma i nVi ew_Cont i nentsVi ew_SouthAmeri canV i ew
lautet. So sollten Anwendungen dieser Art entwickelt werden.
ln den beiden Listen Rounded Rectangl e und Edge - to - Edge lässt sich in der Schnitt
stellenentwurfsansieht in Dashcode nur der j eweils erste Eintrag auswählen. Er dient als
Vorlage für die anderen Einträge. Alle Farb-, Inhalts- oder Größenänderungen, die Sie an
ihm vornehmen, werden auf die übrigen Listenelemente übertragen. Dazu gehören auch
die Ereignislistener, die Sie zuweisen. Alle Elemente in den Listen der Anwendung H i s to r y
haben denselben Listener für Klickereignisse, nämlich die Funktion cha n geV i ew.
Die Funktion c hange V i ew steht in der Datei ma i n . j s und kommt im folgenden Code vor. Sie ermittelt mith ilfe der im Attributbildschirm des Informationsfensters der Ansicht ein
gegebenen Label und Werte, welche neue Ansicht angezeigt werden soll. Um die Funktion
einzusehen, wählen Sie nicht das erste Labelelement aus, sondern die Ansicht selbst. ln
Ihrer Anwendung ist dies die Stelle, an der Sie statische Listenelemente hinzufügen, wie
Sie in Abbildung 3-4 sehen.
@) ()() """"Y""""'""' ~. II CJ.
Au fehrc:n '~"''t o.f)(t1h.lfl9
.. E!!I ( (I(;tcf'lt
,.(E) t.-o ... ::;er
.. 8ht~~tl ~ Q:J ~l.l&l.ayoul
• S rt~l,..\l!tw
o- (i3 Pt-u .dc1n 'lie ...
o- (3 lth1oriu lri911U:)V •.
o- {3 COtltifl(fll$ViC:w
.. 83 SoJtl\>\mt"u~v,e.,..
U we: bd ip-S)'tl'lbol
-
:=
~- :: @ G'.' 111 {!: >:!
Presidan1s
Historlcal Flgures
Continents
Cantries
HistoricaJ Places
.,. Abbildung 3-3: Die Anwendung Hi s t oryExamp l e mit Ansichten und zwei Listen in Form
abgerundeter Rechtecke innerhalb der Hauptansicht
73
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
f unction changeVi ew( event ) {
var subVi ewName = event. t arget .obj ect.val ue; va r displayName = event. t arget . i nnerText; var br owser = document.get Elementßy i dC'browser' ) .obj ect; browser .goForward( subVi ewName+'View'. di splay Name) ;
Verwenden Sie diese Werte und benennen die Ansichten entsprechend, wechselt die Me
thode go Forwa r d des Obj ekts b rowse r korrekt zur nächsten Ansicht. Die Methode weist
zwei Parameter auf Der erste ist der Name der Ansicht, zu der geschaltet werden soll,
der zweite der im Header der Ansicht anzuzeigende Text. Wenn Sie versuchen, zu einer
Ansicht umzuschalten, und sich zwar der Header, aber nicht die Ansicht ändert, ist der
Name der Zielansicht in Ihrer Anwendung nicht vorhanden.
' ~ H i!otOryEJC.tn.p le
-r (3c:etltent
, 8 bi.O'Nfi(t'
•8 hudtr
• tä stael<LJ.;oout
•EJ rn~TIV<(W
.. Eil p!uu
,. 8 f'l'e!oiGt'ltSVitM
,. 8 H•S(~fiC.1!f • 9~o~f~SV<
"' 8 (OIIIIOl'tltSYttW
• (3 S&;t'liAfl'e~tUrV~
0 · :: 0 E:
~~ Llo~_ l I I I I I I l.~öl; I I I I I I I j0
1 I I I I I I I I itb_? I I I I I I I lzbJ I I I I I I I j ~!);' I I I I I I I j4U I I I I I I I j~i I I Ii
t " t r
r= w ~
;
~0 ~ ~ :: r! " c ~
Lß
~-
~ r-. ~~ c E ~ ü
P' c r F ~ ~ c
1111!: >=
() "' r. Attr Outc (oeoo;:~ d
~ r9 ..9 T ~ G
Klasse
AnU:iQ(I ~ !iclub.u "-"'=~----=---! lt . .S:...IiJ.otdtt.IJ.ltl.!e.<.cn
Historical Figures
Continems
Contrtes
Historical Places
C Ocslorr-Gv.c!e
Allswahl ei Au~W:l'll .3iro\'1f!l'en
J "4e"l·e•cer.~~obt
~ l.etfc- Ct lt ubM
Coru;nenu
6utidillu,mg Wtrt Pre!Oid :llt! P1uide.nt~
,, tt iSrofieal r-i9u·e' Hlu Otlc;JiriOu ti!S
"" Abbildung 3.4: Die Anzeige der Personenlistenattribute von mainView mit zwei hinzugefügten statischen Elementen
74
Anwendungen mit nicht auf üsten beruhenden Ansichten
Achten Sie beim Erstel len von Iisten- und ansichtsbasierten Anwendungen darauf, die
Daten korrekt anzuordnen. Sind die Informationen in zu vielen Ansichten verstreut, emp
findet der Benutzer die Navigat ion als übermäßig mühsam. Gehen Sie nicht sorgfä ltig
vor, erfinden Sie möglicherweise die auf DOS beruhende Navigationssteuerung aus den
197oer- und 198oer-Jahren neu.
Für Iisten- und ansichtsgestützte Anwendungen gibt es viele Einsatzgebiete, aber sie sind
nicht unbedingt die optisch ansprechendsten. Gelegentlich ist etwas anderes als eine
Liste erforderlich, um den Wechsel der Ansicht auszulösen. Solche Anwendungen werden
als Anwendungen mit nicht auf Listen beruhenden Ansichten bezeichnet.
3.3 ANWENDUNGEN MIT NICHT AUF LISTEN
BERUHENDEN ANSICHTEN
Obwoh l Iisten- und ansichtsgestützte Anwendungen zahlreiche Einsatzgebiete haben,
gibt es keine Regel, nach der al le ansichtsgestützten Anwendungen für den Zugriff auf
Informat ionen Listen benutzen müssen. Andere optische Indikatoren können darauf
hinweisen, dass bei Berührung eines Elements weitere Informationen angezeigt werden.
Die Beispielanwendung Pi cture Examp l e im QuickConnectiPhone-Download enthält
solche Hinweise.
Wird auf dem Display darauf hingewiesen, dass etwas berührt werden soll, neigt der
Benutzer dazu, Dinge zu berühren, um zu erfahren, ob sie aktiv sind. Wählen Sie diesen
Ansatz, sol lten Sie darauf achten, die Zielbenutzer durch diese Hinweise oder durch das,
was sie zum Steuern der Anwendung berühren sollen, nicht zu verwirren.
Der folgende Code unterscheidet sich in einigen Punkten vom vorhergehenden. Zum ers
ten benötigt jedes Bild entweder einen onc l i c k- oder einen ontouchs ta rt -Listener, um
eine Änderung an einer Unteransicht auszulösen. ln diesem Beispiel werden beide berühr
baren Bilder von einer einzigen Funktion, goSub, behandelt.
function goSub(event) {
var stacklayout = document.getEl ementBy l d( ' stack l ayout') .object; stack l ayout.setCurrentView(event . target .id+' View ' . fa l se ) ;
Dadurch, dass jedes Bild eine ID hat, die dem Namen der Ansicht entspricht, fü r die es steht,
ist es kein Problem, nur eine Methode zum Wechseln der Ansicht zu benutzen. Wie das
vorstehende Beispiel zeigt, hat das Stacklayout-Objekt eine Methode setCurrentV i ew,
75
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
die zwei Parameter übernimmt: die ID der Ansicht, zu der gewechselt werden soll, und
ein Flag. Ist das Flag auf t r ue gesetzt, gibt es an, dass der beabsichtigte Wechsel rück
wärtsgerichtet ist. Die beiden Parameter geben dem Programmierer die Möglichkeit, das
Verha lten der Übergänge zwischen den Ansichten zu steuern.
Im Unterschied zur Anwendung Hi st oryExampl e, die aus einer vorher erstellten Liste,
Ansichten und einem Navigationsheader besteht, besitzt die Anwendung Pi c t u re Exa mp l e
keine integrierte automatische Navigationsleiste. Deshalb muss der Programmierer, der An
sichtswechsel von einer untergeordneten zurück zu einer übergeordneten Ansicht vorsieht,
den Code selbst schreiben.
Anders als die Bilder in der Hauptansicht sollen die BACK-Bi lder einen Wechsel zur Haupt
ansicht veranlassen. Da es ungeschickt ist, einen rückwärtsgerichteten Übergang genau
so aussehen zu lassen w ie einen vorwärtsgerichteten, erhä lt der zweite Parameter der
Funktion setCur rentV i ew den Wert true, was besagt, dass ein rückwärtsgerichteter
optischer Übergang erforderlich ist.
Der folgende Code von goMa in ist als on c l i c k-Listener mit der Scha ltfläche BACK ver
knüpft. Ihm wird als zweites Argument true übergeben, was dazu füh rt, dass der mit
ma in Vi ew verkn üpfte Übergang in umgekehrter Richtung wie das Standardverhalten ab
läuft. Auf diese Weise ist es mögl ich, dem Benutzer den Eindruck zu vermitteln, dass eine
vorhergehende Aktion rückgängig gemacht w ird.
f unction goMain (event ) {
II Di e aktuell e Ansicht ei nes Stackl ayout s f est l egen var Stack l ayout = document.get El ementßy l d( ' sta ckl ayout ' ) . obj ec t ; sta cklayout.setCur r entView( ' ma i nView', true) ;
Ein weiterer Unterschied zu browsergestützten Anwendungen sind die Optionen für die
Art der Animierung des Übergangs beim Wechsel der Ansicht. Sie ähneln den übrigen
Informationen, die der Benutzer bekommt. Wird für den Übergang zu einer Ansicht ein
anderer Typ gewählt als für die anderen, ist mit dieser Ansicht etwas anders. Abbildung 3-5
zeigt die Liste der Unteransichten und die Funktion goMai n in Dashcode.
Wie in Tabelle p gezeigt, können Sie in Ihren Anwendungen mehrere Übergangsarten ver
wenden. Es ist zwar möglich, eine Vielzahl von Übergängen einzusetzen, wäre aber unklug.
76
Anwendungen mit nicht auf üsten beruhenden Ansichten
~ !!,. EJ. AUsfGII~n ravs~ DotfSt~lung
·~intf02 • Gh )taÖ~I
• EJ nui!IV~w @S I.ondon
'ir UXl
~ Yelicrwuone
~ttl<t!
'E tfXI1
"EJ Lo•!don'v~ew
l!!l tmo5 l'$ buu <rl
~ lnl9
~ !mgl @!! o t~lg !
(g imgZ
@! 11'119"'
Jt li,u'<CiOM jS
'!• lfldt X.html
c• m.:in,<H
~ mdnJs ;s m.)l)l)inps.,s
~ ... '·'"'
II II r41ncliot~ locd() II Col'hd by lfnoll bti!Cy "\D'Mint ' ~; cntoad .. vont "'""" t-M v.flb II ( un.::tton leodO (
ful'lc·h o l'l goSuO(ovtn t ) (
vor ~tcckLayout .. docU!I!Cnt . geH lementiyld( ' ~tccktayout' ) .objecl; s tockloyout:. sttCvrf' tntVi.tlll(evtnt. tof'get. t d .. ' Yi nr' ):
AU! DUtt Ul~(~l3~·0~oU
c9&> T ~e
to ~utld...syout
Allttlgt E:1 Si tiltO.lf
Subview,
10
,." S.tl .. CJtl'lb Cl .1r2to~r
O outon-Gutde
G] rnJ.!nVICW
8 LondonV!ew
l3 Vcllow~toneVitw
~o .._ QCoP'hOI"'e ~-
( unctton gclNot n(event ) ( tlber'g3.rtg (SubV1Ew)
~~r s::o~~~o~~:~~t d:~:C~~ . :c::~r:~~~~~~d{ ' slc(kLoyowt' ) .objc:~t ; ~ -""',.-,-'"".."'--,"'.,.."-,'"' ""'"""'~~q stcu::lcl.oyout . ntCvrr(lntvio•('no\nV\(>~' , trvt): O..u.er 0.55 r:) s.ea:uAden
2titv<:r hod t c:n Hincirt-/Hin.aw5bt'""C9<:n 1)
~ Abbildung 3.5: Der Bildschirm Stacklayout Attributes mit dem Übergang
Quelle: http:! /creativecom mons.org!/icenses!by-sa/3. o!deed.de
Übergangstyp Verhalten
push (verschieben) Ein zweidimensionaler Übergang, bei dem sich die
anzuzeigende Ansicht in den sichtbaren Bereich schiebt,
während die alte ihn verlässt.
d i sso l ve (auflösen) Ein zweidimensionaler Übergang, bei dem die anzuzeigende
Ansicht undurchsicht iger w ird, die alte dagegen durchsichtiger.
s l i de (schieben) Ein zweidimensionaler Übergang ähnlich wie pus h. ln diesem
Fall bleibt die alte Ansicht an Ort und Stelle, während die neue
von oben darüber zu gleiten scheint. Der Benutzer gewinnt den
Eindruck, sich durch einen Stapel von Ansichten zu bewegen.
ln diesem Fall bedeutet ein rückwärtsgerichteter Wechsel, das
Heruntergleiten, eine Abwärtsbewegung durch die Ansichten der
Anwendung, ein vorwärtsgerichteter Wechsel, das Hinaufgleiten,
dagegen eine Aufwärtsbewegung durch den AnsichtsstapeL
77
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
fade (überblenden) Ein zweidimensionaler Übergang ähnlich wie di s sol ve. ln
diesem Fall bleibt die alte Ansicht undurchsichtig, sodass
am Sch luss des Übergangs beide sichtbar sind. Erfolgt dieser
Übergang »rückwärts«, wird die neue Ansicht undurchsichtig,
und die ursprüngliche wird vol lständig angezeigt. Dieser
Übergang dient dazu, neue Informationen oder Funktionen
in eine Ansicht einzufügen, wei l beide Ansichten auf
Berührungsereignisse reagieren können.
f l i p (umdrehen) Ein dreidimensionaler Übergang, der eine Drehung um die
y-Achse des Geräts durch das Zentrum der alten und der
neuen Ansicht auslöst. Der Benutzer gewinnt den Eindruck,
die alte Ansicht sei die Vorderseite der Anwendung, die
neue die Rückseite. Dieser Übergang w ird normalerweise in
Anwendungen mit nur zwei Ansichten verwendet.
cube (Würfel) Ein dreidimensionaler Übergang, der fü r den Benutzer so
aussieht, als befänden sich alle Ansichten auf den Seiten eines
Würfels, der sich vor- und zurückdreht.
swap (vertauschen) Ein dreidimensionaler Übergang, bei dem die alte Ansicht zu
einer Seite zu gleiten und sich dann unter die neue Ansicht zu
schieben scheint. Während des Vorgangs ist der Hintergrund
der neuen Ansicht transparent; er wi rd beim Abschluss
undurchsichtig.
revo l ve (rotieren) Ein dreidimensionaler Übergang, bei dem sich die alte und die
neue Ansicht auf der y-Achse des Gerätedisplays um eine Seite
zu drehen scheinen. Der optische Eindruck ähnelt einer Drehtü r.
Tabelle 3.2: Standardübergänge in Dashcode
Die Dashcode-Schnittstelleerwecktden Eindruck,dass nurdie Richtungen r i ght - to - 1 eft
und l eft - t o - r i ght für diese Übergänge zur Verfügung stehen, die sich bewegen. Das stimmt nicht: Auch top - to - bo t tom und bo t t om - to - top ist möglich.
Der folgende Code stammt aus der Datei setup . j s der Beispielanwendung History Examp l e. Er wird von Dashcode erstellt. Wie Sie sehen, fi nden Sie hier die Über
gangstypen und ihre Richtungen für sämtliche Ansichten. Wol len Sie sie ändern, müssen
Sie zuerst die Codeerstellung ausschalten. Dazu benutzen Sie in Dashcode die Option
( ODE-G ENE RATOR STOPPEN des Pu II-down-Menüs DARSTELLUNG.
78
Anwendungen mit nicht auf üsten beruhenden Ansichten
var das hcodePartSpecs
" stack l ayout " : { " creati onFunction": "CreateSta ckl ayou t " , " subviewsTransitions": [ { "di rect ion " : "r ight-left " , "dura tion": n "
"timi ng": "ease - in-out ", "ty pe": "pus h" } , { "direction ":" right-left" ,
"duration":" ", "timing": "ease-in-out", "type ": "push" }, {
"direct i on": "r ight - left", "durat ion ": "", "t iming " : "ease- i n -out", " type ": " push " }, { "d i rect ion": "r i ght- l eft", "duration": " " , " timi ng": "ease - in-out", "ty pe": "pus h" }, { "direct ion ": "rightl eft", "dura t ion " : '"' , " t i ming " : "ease - i n - out ", " t ype " : "pus h" } ] }
} ;
Da Dashcode ziemlich viel Code fü r Sie erstellt und den Inhalt der Datei setup . j s re
gelmäßig aktua lisiert, sollten Sie diese Datei erst ändern, wenn Ihre Anwendung fert ig
ist. Am einfachsten geht es, nachdem Sie sie in der Xcode-QuickConnectiPhone-Vorlage
untergebracht haben, wei l Dashcode dann nicht mehr beteiligt ist und deshalb keine
Änderungen Ihrerseits überschreiben kann. Möchten Sie die Datei bereits in Dashcode
ed it ieren, sol lten Sie aus dem Pu l I-down-Menü Da rs te l l ung den Eintrag Dateien auswäh len. ln der darauf erscheinenden Liste der Projekt dateien fi nden Sie im Unterordner
Parts u.a.die setup.js-Datei.
Der vorstehende Code ent hält die Deklaration von vier JavaScript-Objekten. Jedes beginnt
mit einer öffnenden geschweiften Klammer ({),endet mit einer sch ließenden geschweiften
Klammer (}) und enthält die Attribute d i rect i on, du ra t i on, t i mi ng und type. Das zweite
Objekt erscheint im Fettdruck, damit Sie es leichter von den anderen unterscheiden können.
Jedes dieser anonymen Objekt e definiert das Verhalten eines Übergangs zwischen
zwei Ansichten. Der fett gedruckte Objektcode deklariert einen Übergang des in Tabel
le 3-2 beschriebenen Typs pus h. Die neue Ansicht schiebt sich mit allmählich steigender
Geschw indigkeit von links nach rechts hinein und bremst am Ende des Übergangs ab (ease - in - out).
79
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Weitere Zeitoptionen lauten ea se - in, eas e- out und de f aul t. Die letzte bedeutet
konstante Geschwindigkeit und wird benutzt, wenn das Attributtimi ng des Übergangs
objekts in der Definition nicht gesetzt ist.
Wie bereits erwähnt, gibt es für die Richtung des Übergangs noch die Optionen
t op- bottom und bo t tom- top, die nicht bei allen Übergangsarten funktionieren, son
dern nur bei s l i de und pu s h.
Entscheiden Sie sich dafür, diese Objektdeklarationen zu ändern, sollten Sie wissen, dass es
Probleme geben kann, wenn Ihre Anwendung komplexer ist. Anscheinend hat Apple keine
Möglichkeit vorgesehen, Opt ionen für die Übergangsdefin it ion zu wäh len, wei l sie zu
Feh lverhalten bei dem in Safari verwendeten WebKit-Modul und dem Objekt UIWebV i ew in Web-Apps führen.
3.4 IMMERSIONSANWENDUNGEN
Anwendungen in Immersionsart bedeuten eine deutliche Abkehr von Ansichten als Mit
tel, um die Anzeige und Steuerung von Informationen in Gruppen zusammenzufassen.
Die gängigste Form derart iger Anwendungen finden Sie in Spielen, aber auch aktuel le
Beispiele von medizinischen iPhone-Anwendungen nutzen diesen Ansatz. Dahinter steht die Auffassung, dass das Zusammenwirken von Benutzer und Anwendung natürlich, fl ie
ßend und nach Mögl ichkeit innerhalb einer Ansicht stattfinden soll.
Obwohl dieser Ansatz in seiner extremen Form in Spielen verwendet w ird, kann er auch
auf andere Art eingesetzt werden. Die medizinischen lmaging-Anwendungen zum Bei
spiel benutzen ihn und die Berührungsfähigkeiten des iPhones, um die Interaktion von
Ärzten mit medizinischen Bildern erheblich zu verändern.
Es gibt keinen Grund daf ür, dass innovative Anwendungsersteller diesen Ansatz nicht im Geschäftsleben oder in der Wissenschaft nutzen sollten. Ein Grund fü r sch lechte Unter
nehmensentscheidungenliegt darin, dass sich miteinander zusammenhängende kompl i
zierte Daten mit den einfachen Diagrammen und Graphen, die heute verwendet werden,
nur schwer sichtbar machen lassen. Um sie auf andere Art zu betrachten, muss eine neue
Methode der Darstellung herangezogen werden.
Lassen sich Daten optisch in einer nichtlinearen Form anzeigen, die den gesamten Bildschi rm
umfasst, können damit zusammenhängende Daten als Overlay benutzt werden, um Bezie
hungen zu finden. Eine einfache Form dieses Ansatzes ist die Fähigkeit der Kartenanwend ung,
nicht nur eine Route von einem Ort zu einem anderen auszugeben, sondern auch die Verkehrsdichte auf und in der Nähe der Route. Dabei werden zwei Informationsteile übereinan
dergelegt, damit der Benutzer ein sinnvolles Muster erkennen kann.
80
lmmersjonsanwendungen
Dieses Buch gibt nicht vor, einen Ansatz f ür die Bearbeitung von Daten f ür die Anzeige zu
liefern. Es legt lediglich nahe, dass es gemacht werden kann und gemacht wird. Als Bei
spiel in diesem Abschnitt dient ein Spiel.
Das SpielDol l a r Sta sh ist eine Variante der Beispiel-Webanwendung Leaves von Apple,
in der eine Folge von Bildern in eine Seite eingefügt wird, die allmäh lich auf den Boden
des Bildschirms fallen und sich dabei winden und drehen. Um daraus ein Spiel zu machen,
wurden aus den Blättern Symbole f ür Geld gemacht.
Berührt der Benutzer einen Schein, dann steigt der Geldbetrag auf seinem Konto um 1.
Wenn ein Schein vollkommen verblasst und verschwunden ist, bevor er berührt wird, sinkt
der Kontostand des Spielers um 1. Am oberen Bildschirmrand erscheinen Gruppen von
Scheinen in Wellen. Jede Welle enthält einen Schein mehr als die vorige. Sinkt der Konto
stand des Spielers unter o, ist das Spiel zu Ende. Abbildung 3.6 zeigt ein laufendes Spiel.
Obwohl das Spiel schnell erstellt w urde, zeigt es deutlich eine der Einschränkungen derar
tiger Anwendungen in einer Webumgebung auf.
~ Abbildung 3.6: Das Spiel DollarStash
in Betrieb
Das Obj ekt U I WebVi ew verwendet dasselbe WebKit-Modul wie Safari und andere Anwen
dungen, um den Bi ldschirm zu berechnen. Dieses und andere ähn liche Module haben in
den vergangenen Jahren erhebliche Fortschritte gemacht. Ein ihnen gemeinsames Prob
lem besteht darin, dass Benut zerschnittstellenereignisse wie Klicks und Berührungen
ignoriert werden, wenn der Prozessor stark belastet wird. Wenn Sie DollarStash nicht im
Simulat or, sondern auf Ihrem Gerät spielen, stellen Sie fest, dass es st immt.
81
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Mit zunehmender Anzah l von Scheinen steigt auch die Anzahl der Berührungen, die das
Modul nicht ausführt. Dem Benutzer solche Unannehmlichkeiten zuzumuten, verletzt
eine Grundregel unseres Schnittstel lenentwurfs, die im ersten Abschnitt dieses Kapitels
genannt wurde: schnel le Reaktion auf Benutzereingaben.
Die benutzeraktiven Tei le dieser Art von Anwendungen lassen sich am besten in Objective-C
schreiben, was nicht heißt, dass Anwendungen kein U I WebV i ew-Modul für komplexes Text
layout oder einfache Bi ldausgaben benutzen können, sondern dass es nicht sinnvol l ist, die nativen (55-Transformationen und -Animationen (Cascading Style Sheet) zum Erstel len
komplexer Spiele zu verwenden, bevor die iPhone- und iPod touch-Prozessoren wesentlich
höhere Geschwindigkeiten erreichen.
Das Wissen um die Einschränkungen Ihres Geräts kann Sie zu besseren Entwürfen füh
ren. Auch wenn in Web-Apps keine prozessorintensiven Spiele rea lisierbar sind, lassen sich
(55-Transformationen und -An imationen für Drag&Drop, Skalierung und Drehung einset
zen, solange nur ein einziges Schnittstellenelement betroffen ist.
3.5 ßENUTZERDEFI NIERTE (55-TRANSFORMATIONEN
ERSTELLEN UND VERWENDEN
in diesem Abschnitt erfahren Sie, wie Sie mithilfe der neuen (55-Transformationen im
WebKit -Modul, das von Safari und dem U IWebVi ew-Objekt benutzt wird, Drag&Drop-,
Skalierungs- und Drehfähigkeiten erstellen. Mehr über CSS-Übergänge, -Transformatio
nen und -Animationen erfahren Sie in der Benutzeranleitung von Apple unter folgender
Adresse: http:l!developer.apple.com/safarilfibrary!documentation/lnternetWeb/Conceptuai!SafariVisuaiEffectsProgGuide!lntroduction/lntroduction.html.
Zum Herunterladen stehen mehrereJavaScript-Umsetzungen des Verhaltens in Drag&Drop
Art zur Verfügung, die sich hervorragend für die browserübergreifende Nutzung auf stati
onären Rechnern eignen. Auf dem iPhone und dem iPod t ouch versagen sie jedoch, wei l sie
prozessorintensiv sind. Eine gute Alternative stellen j edoch (55-Transformationen dar. Web
Kit, das von Safari und U I WebV i ew in Web-Apps verwendete Modul, kann Übergänge in CSS definieren. Sie sind hardwarebeschleunigt, wodurch sie effizienter werden als Änderungen
mithilfe von JavaScript wie in anderen Bibliotheken.
Ein einfaches Beispiel ist das Verschieben eines HTML-d i v-Eiements nach unten. Mit
herkömmlichem JavaScript müssen Sie das Attribut top des d i v-Styles verändern. Ange
nommen, dem d i v ist eine CSS-Kiasse zugewiesen, die das Attribut auf so Pixel von der
Oberkante der Seite setzt, dann wi rd eine Verschiebung um weitere so Pixel nach unten
erreicht, indem man das Attri but auf 100 Pixel setzt:
adi v.sty l e.top = ' lOOpx';
82
Benutzerdefin ierte ( 55-Transformationen erstellen und verwenden
Diese Deklaration wird als JavaScript-Befehl interpretiert und vom Modul mit derselben
Geschwindigkeit und denselben Prozessorressourcen ausgeführt wie jeder andere JavaScript-Befehl. Die (55-Transformation als Alternative funktion iert anders.
(55-Transformationen für eine Änderung der ursprünglich deklarierten Position um so Pixel erfordern ebenfalls die Verwendung der Deklaration des d i v-Stils; es wird jedoch ein
vollkommen anderes Attribut benutzt.
Eins der neuen Attribute in CSS-Kiassen und deshalb auch ein Stilattribut von Element
objekten in JavaScript ist webKi tTransform. Korrekt gesetzt ruft es hardwarebeschleu
nigte native Funktionen auf. Es w ird nicht als JavaScript interpretiert, weshalb definierte
CSS-Attributänderungen wesentlich schneller ausgeführt werden als im vorstehenden
JavaScript-Beispiel.
Das hier gezeigte Beispiel fü r eine Transformation benötigt ebenfa lls nur eine Codezeile:
adiv.styl e.webKitTransform = ' trans l ateY(50px) ' ;
Aufden ersten Blick scheint das Transformationsattribut ein Funktionszeigerwie on c l i c k,
ontouc h und andere Ereignislistener zu sein, ist es jedoch nicht.
Der wesentliche Unterschied zwischen webK i tT ra n s form und den Ereignislistenern be
steht darin, dass keine innerhalb der Zeile oder als Fensterf unktion deklarierte JavaScript
Funktion zugewiesen wird, sondern einString mit einer Beschreibung, welche Standard
funkt ion mit welchen Parametern aufgerufen werden soll. Anschließend w ird dieser
String vom WebKit-Modul in einem Codeabschnitt analysiert, in dem keine JavaScript
l nterpretat ion stattfindet.
Beachten Sie außerdem, dass der deklarierte Betrag derVersch iebu ng relativ zur ursprü ng
lichen Position des d i V-Elements ausgedrückt ist. Der Parameter fürtrans l ateY ZurVer
sch iebung eines Elements um so Pixel nach unten lautet 50 px. Außerdem ist w ichtig, dass die Originaldefin it ion der Position nicht geändert wurde. Dem d i v wi rd im mer noch
der Originalwert 50px fü r top zugewiesen. Geändert hat sich nur die Position, an der
es wiedergegeben wird. Fragen Sie das Objekt nach der Verschiebung ab und geben den
Wert top aus, lautet er weiterhin nicht lOOpx, sondern 50 px.
Die Beispielanwendung Drag zeigt, w ie ein div-Eiement mithilfe einer trans l ate
Funktion veranlasst wi rd, sich über das Display zu bewegen. Dazu werden dem zu ver
sch iebenden Element Listener für die Ereignisse ontouc hsta rt, ontouchchange und
ontouc hend zugewiesen.
Berührungsereignisse unterscheiden sich von den in herkömmlichen Drag&Drop-lmple
mentierungen in JavaScript verwendeten Standardereignissen onc l i ck, onmousedown
und onmouseup. Da eine Berührung aus zwei oder mehr einzelnen Berührungen beste-
83
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
hen kann, beispielsweise wenn ein Benutzer zwei oder mehr Finger auf das Display legt,
muss ein Berührungsereignis Informationen über jede einzelne Berührung enthalten.
Jede einzelne Berührung w ird mit ihren Daten in einem Array abgelegt, das ein Attribut
eines Ereignisobjekts mit dem Namen ta rgetT ouches ist. Die Größe dieses Arrays ent
spricht der Anzahl der Finger, die der Benutzer auf das Element auf dem Display gelegt
hat. Ist es nur ein Finger, beträgt die Größe des Arrays also 1, bei zwei Fingern 2.
Jedes im Array gespeicherte Obj ekt ist vom Typ Touch und besitzt viele der Attribute, die
üblicherweise mit einem Mausereignis in JavaScript verknüpft sind. Tabelle 3-3 beschreibt
die einzelnen Attribute.
Die hier gezeigte Drag&Drop-Umsetzung benutzt die Attribute cl i entX und cl i entY,
weil in der Beispielanwendung kein Bildlauf zulässig ist. ln Verbindung mit Bildlauf wer
den die Attri bute pageX und pageY verwendet.
Attribut
pageX
pageY
sc reen X
sc reenY
c l i entX
c l i entY
target
Beschreibung
Horizontalabstand von der linken Seite des Gesamtdokuments
einsch ließl ich horizontaler Bi ldlaufdaten
Verti kalabstand von der Oberkante des Gesamtdokuments
einsch ließl ich vert ikaler Bild laufdaten
Horizontalabstand von der linken Seite des Gerätedisplays
Verti kalabstand von der Oberkante des Gerätedisplays
Horizontalabstand von der linken Seite des Anwendungsfensters
Verti kalabstand von der Oberkante des Anwendungsfensters
Das DOM-Objekt fü r das berührte HTML-Eiement
Tabelle 3-3: Attribute der Klasse Touch
Ein Problem bei der Umsetzung von Drag&Drop ste llen »hüpfende« Elemente dar, die zu
Beginn des Ziehens auftreten. Das Hüpfen erfolgt, weil der Benutzer das Obj ekt durch
Berührung irgendwo innerhalb seiner Grenzen ausgewählt hat, die Verschiebung jedoch
auf die linke obere Ecke angewendet wi rd. Wird diese Unterschiedlichkeit nicht behandelt,
»hüpft« die linke obere Ecke des gezogenen Objekts an die Ste ll e, an der der Finger des
Benutzers zu Beginn des Ziehvorgangs liegt.
84
Benutzerdefin ierte ( 55-Transformationen erstellen und verwenden
Der Benutzer betrachtet dies natürlich als nicht normal. Wählt er beispielsweise den Mittelpunkt des Objekts aus, um den Vorgang zu starten, erwartet er vernünftigerweise, dass sein Finger während des Ziehens im Mittelpunkt verbleibt. Alles andere wirkt verwirrend. Abbildung 3·7 zeigt die Beispielanwendung Drag in Betrieb.
Um dies zu beheben, weist die Beispielanwendung dem JavaScript-Ereignishandler ontouch sta rt die Funktion setSta r tlocat i on zu, die Sie im folgenden Code und in der Dateimai n. j s des Beispiels finden. Sie fragt die Position des ursprünglichen Berührungsereignisses in x- und y-Richtung von der linken oberen Ecke des Anwendungsfensters in Pixeln ab und speichert sie.
1 funct i on setStar t l ocat ion( event ) 2 { 3 var el ement = event . ta rget; 4 el ement.offsetX event . ta r getTouches [O ].cl i entX; 5 el ement.offsetY = event . ta r getTouches [O ].cl i entY; 6
Indem sie diesen Abstand in Form der Attribute offsetX und offsetY des berühr
ten Elements festhä lt, kann er später beim Ziehen des Elements benutzt werden, um
das Hüpfen zu verhindern. Die eigentl iche Bewegung des Elements erfolgt nicht in der Funktion setSta r tlocat i on, sondern in der Funktion drag, die als Ereignislistener ontouch chan ge zugewiesen w urde. Sie steht ebenfal ls in der Datei ma i n. j s.
I I
~ Abbildung 3-7: Die Beispielanwendung Drag nach der Verschiebung des grünen div-Eiements
85
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Wie im folgenden Code gezeigt, ist Zeile 3 in der Ziehfunktion wesentlich für alle Drag&DropUmsetzungen für iPhone und iPod touch. Wenn ein Änderungsereignis aufgrund von Berührung ausgelöst wird, erfolgt im Browser Safari oder in UIWebView normalerweise ein Bildlauf Um dieses Verhalten auszuschalten, muss das Ereignis eine entsprechende Anweisung erhalten, was durch den Aufruf der Ereignismethode preventDefaul t ge
schieht. Wird die Methode innerhalb eines ontouc hchange-Listeners aufgerufen, läuft die Ansicht bei einer Fingerbewegung innerhalb des Elements, dem der Listener zugewiesen ist, nicht weiter.
Die Befreiung vom Standardbildlaufverhalten gibt Ihnen die Möglichkeit, die Position, an der das Element wiedergegeben wird, mith ilfe von webKi tTransform zu ändern. Dazu
muss die aktuelle Position der Berührung festgestellt und mit der ursprünglichen verglichen werden, die in der Funktion setSta rtlocati on abgelegt ist.
1 function drag(event) 2 { 3 event .p reven t Defaul t ( ) ; 4 var el ement = event . t arget; 5 el ement.x event . targetTouches [ O].c l ientX 6 - event .target.offsetX: 7 el ement.y event . targetTouches [ O].c l ientY 8 - event.target .offset Y: 9 if( el ement . l astX I I el ement . l astY) { 10 el ement.x += el ement. l astX; 11 el ement.y += el ement. l astY : 12 13 el ement . sty l e .webkitTransform = ,trans l ate ( . 14 + el ement.x + ,px, . 15 + el ement.y + . px)': 16
ln Zeile 5 bis 8 des vorstehenden Codes wird der Betrag f ür den Abstand in x-u nd y-Richt ung bei der Wiedergabe des Elements berechnet. Diese Abstände in Pixeln werden zur
späteren Verwendung in den Attributen x und y des aktuellen Elements gespeichert und anschließend in Zeile 13 bis 15 fü r die Änderung der Anzeige mithilfe der bereits beschriebenen Funktion trans l ate benutzt.
Da dieser Ziehvorgang möglicherweise nicht der erste ist, den der Benutzer für ein Element durchgeführt hat, ist es erforderlich, die früher verwendeten Abstände zu verfolgen
86
Benutzerdefin ierte ( 55-Transformationen erstellen und verwenden
und zu berücksichtigen. Sie werden in Zeile 9 bis 11 des vorstehenden Codes angewendet
und in der Methode done abgelegt, die folgt. Sie ist als Listener ontouch zugewiesen.
function done(event ) {
var el ement = event.target; element. l astX el ement . x: element. l astY = el ement .y ;
Die Methode done ist nur aus einem einzigen Grund vorhanden: um den aktuellen Betrag
des Abstands zu speichern, falls der Benutzer das Element noch einmal zieht. Dazu legt
sie die aktuellen Attribute x und y des Elements in den Attributen l astX und l astY ab.
Dadurch stellt sie sicher, dass sie verfügbar sind, wenn der Benutzer seinen Finger über
das Display bewegt und eins der on t ouc hc hange-Ereignisse ausgelöst wi rd.
Dadurch, dass Sie diese drei Methoden als Listener in die Elemente Ihrer Benutzerschnitt
stel le eingefügt haben, kann der Benutzer die Elemente auf einfache Art ziehen. Im nächs
ten Abschnitt erfahren Sie, w ie Sie ein leichterverwend bares, wen iger banales Drag&Drop
Modul erstel len und einsetzen.
Außer Drag&Drop benötigen iPhone-Anwendungen häufig die Fähigkeit , Elemente der Schnittstelle zu skalieren und zu drehen. Dabei kann es sich um d i V-Elemente, Schalt
flächen, Bilder oder andere Anordnungs- oder optische Elemente handeln. Der dazu erfor
derliche Code ist interessanterweise wesent lich knapper alsfür Drag&Drop. Es ist kla r, Apple
möchte, dass Techniker und Entwickler dieses Verhalten in ihre Anwendungen integrieren.
Die Beispielanwendung Gestures zeigt, wie sich Ska lierung und Drehung einfach verwirk
lichen lassen. Gesten unterscheiden sich von Berührungen darin, dass sie grundsätzlich von
der Betei ligung mehrerer Finger ausgehen und Benutzerverhalten w ie Pinch einschließen.
Um diese Gesten darzustellen, wi rd ein GestureEvent an eine auf Gesten lauschende
Funkt ion übergeben. Weil es sich um Gesten handelt, entha lten diese Ereignisse keine
Positionsinformationen wie Berührungsereignisse. Wie Sie in Tabel le 3·4 sehen, umfassen
sie drei interessante Informationen.
87
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Attribut
sca l e
Beschreibung
Ein positiver oder negativer doubl e-Wert, der die Abstandsänderung
zwischen zwei Fingern wiedergibt, die bei einer Geste benutzt werden.
Negative Werte besagen, dass die Finger gekreuzt sind. Dieses Attribut
wird bei der Behandlung von Pinch-Gesten verwendet.
rota ti on Ein positiver oder negativerdoubl e-Wert in Grad, der den Drehabstand
zwischen der Position von zwei Fingern und einer senkrechten Linie
wiedergibt, die bei einer Geste benutzt werden. Dieses Attribut w ird bei
der Behandlung von Drehgesten verwendet.
target Das DOM-Objekt für das HTML-Eiement, in dem die Geste erfolgt ist.
Tabelle 3.4: Die wichtigen Attribute von GestureEvent
Die Beispielanwendung Gestures verwendet diese drei Ereignisse, um ein d i V-Element
zu skalieren und zu drehen. Dazu fügt sie dem Element selbst einen onges t urechange
Ereignishandler mit dem Namen changelt hinzu. Dies geschieht mithilfe der Register
karte Beha v i o rs des lnformationsfensters. Der Code dafür lautet wie folgt:
function change l t ( event) {
event . pr even t De f aul t () ; var el ement = event.ta rget;
el ement.sty l e . webki t Tr ansf orm= ' r otateZ ( '+event .rotat ion + ' deg ) sca l e( ' +event.scale+ ' ) ':
Beachten Sie, dass das Standardverhalten des Ereignisses genau wie in der Beispiel
anwendung Drag ausgeschaltet werden muss, um den Bi ldlauf zu verh indern. Im Gegen
satz zur Anwendung Dr ag werden die Dreh- und Skalierungsdaten nicht gespeichert. Das
Speichern der Drehinformationen ist nicht erforderl ich, weil es nicht relativ zum transfor
mierten Obj ekt, sondern zu einer Grundlinie erfolgt.
Die Skalierungsdaten sollten gespeichert werden, damit sie bei der nächsten Geste be
nutzt werden können, wei l sie relativ zum transformierten Element sind und kumulativ
w irken. ln der Beispielanwendung und im vorstehenden Code wurde darauf verzichtet,
um Ihnen den Skal ierungsfehler zu zeigen, den der Benutzer der Anwendung sieht, wenn
es nicht geschieht. Der nächste Abschnitt zeigt Ihnen, wie Sie Skal ierungsdaten speichern
und wiederverwenden.
88
Benutzerdefin ierte ( 55-Transformationen erstellen und verwenden
Beachten Sie, dass in dem String, der das Attribut webKi t Tra ns form defin iert, zwei Funk
tionen benutzt werden. Damit können Sie das d i V-Element in einem Aufruf drehen und
ska lieren. Sie lassen sich auch trennen und bedingt einsetzen.
Beim Erstellen Ihrer Anwendung stehen Ihnen drei Drehfunktionen zur Verfügung. Jede
dreht das Element Ihrer Wahl um eine der Achsen Ihres iPhones. Die x-Achse verläuft
horizontal, die y-Achse vertikal, und die z-Achse ragt aus dem Display heraus. Die Funktion
rota teZ besagt, dass sich das d i v-Eiement auf der x-y-Ebene des Geräts drehen soll wie
in Abbi ldung 3-8.
~ Abbildung 3.8: Die Funktion rotatel von webKitTransform
Die Drehung lässt sich leicht ändern, sodass sich das d i v-Eiement anders dreht. Verwen
den Sie im Beispiel rotateY, dreht es sich um die y-Achse und scheint näher zu kommen,
bevor es seine Rückseite zeigt. Ändern Sie die Drehung in r otateX, dreht sich das d i V
Element um die x-Achse und scheint kürzer zu werden, bevor es seine Rückseite zeigt.
Möglicherweise erwägen Sie, mithilfe der Drehung einen Cover-Fiow zu implementieren.
Als dieses Buch geschrieben wurde, war dies nicht ratsam. Wegen der für ein derartiges
Verhalten erforderlichen Anzahl von Transformationen überlastet jede Umsetzung den
iPhone- oder iPod touch-Prozessor, sodass der Benutzereindruck unbefriedigend ausfällt.
Nachdem Sie bisher banale Implementierungen von Drag&Drop, Ska lierung und Drehung
kennengelernt haben, sind Sie in der Lage, ein ausgefeiltes Umsetzungsmodell zu verstehen.
89
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
3.6 EIN MODUL FÜR DRAG&DROP, SKALIERUNG UND
DREHUNG ERSTELLEN UND VERWENDEN
Wie in Kapitel2, »Die Modularität von JavaScript für iPhone-Anwendungen«, beschrieben,
sind Module in ihren Funktionen vollständig und unabhängig. Anders ausgedrückt: Sie
sind lose an den übrigen Code der Anwendung gekoppelt und weisen engen Zusammen
halt auf. Gut gestaltete Module sind mit einer API ausgestattet.ln Tabelle 3-5 sehen Sie die
API, die in diesem Abschnitt implementiert wird.
Funktion Parameter Beschreibung
ma keDraggable e l emen t (erforderlich)- Diese Funktion richtet die das zu ziehende DOM-Element Ereignisl istener für das
sta rtDragCmd (optional) -übergebene Element ein,
ein Befehl, der Steuerfunktionen sodass der Benutzer es
zugewiesen wi rd, die am Ende ziehen kann.
des Ereignisses on t ouchsta rt
aufgerufen werden
dragCmd (opt ional)-ein Befehl, der
Steuerfunktionen zugewiesen w ird, die am Ende aller ontouc hmove-
Elemente aufgerufen werden
d ropCmd (opt ional)- ein Befehl,
der Steuerfunktionen zugewiesen
w ird, die am Ende des Ereignisses
on t ouchend aufgerufen werden
ma keChangeabl e e l emen t (erforderlich) - Diese Funktion richtet
das zu skalierende und zu drehende die Ereignisl istener für DOM-Element das übergebene Element
sta rtChangeCmd (opt iona l)-ein, sodass der Benutzer
ein Befehl, der Steuerfunktionen es skalieren und um die
zugewiesen wi rd, die am Ende x-Achse drehen kann.
Der Benutzer kann damit des Ereignisses ongesturesta r t
hoffentlich nicht skaliert aufgerufen werden
werden!
90
Ein Modul für Drag&Drop, Skalierung und Drehung
{Fortsetzung) d ragCmd (optional)- ein
Befeh l, der Steuerfunktionen
zugewiesen wird, die am Ende aller ongesturechange-Eiemente
aufgerufen w erden
doneChangeCmd (optiona l)-
ein Befehl, der Steuerfunktionen
zugewiesen wird, die am Ende
des Ereignisses engestureend
aufgerufen werden
Tabelle 3-5: Die API für Drag&Drop, Skalierung und Drehung
Diese beiden Funktionen sind alles, was der Code aufrufen muss, um Ihrem Benutzer
Drag&Drop, Skalierung und Drehung zu ermöglichen {siehe Abbildung 3-9). Die Beispielanwendung dragAndGes t ure finden Sie im Verzeichn is Exampl es, das Sie als Teil von
QuickConnectiPhone von folgender Adresse herunterladen können: https:l/sourceforge.netl project/showjiles.php?group _id=213586.Die Funktionen stehen in der Datei QCUt i l i t i es. j s
des Framewerks im selben Download.
~ Abbildung 3.9: Die Beispielanwendung dragAndGesture wird ausgeführt und ein Element gedreht und verschoben.
91
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Die Ladefunktion aus der Datei ma in . j s, die im folgenden Code enthalten ist, zeigt, wie
diese Funktionen für Elemente in einer Benutzerschnittstelle eingesetzt werden.
f unct ion l oad()
var an El ement = document .get ElementByld( ' button ' ) ; makeDraggable(anElement); makeChangeabl e(anElement); anElement = document.get El ementByld('imageßox'); makeDraggabl e(anElement); makeChangea bl e(an El ement);
anEl ement = document.get El ementßyld('box' ) ; makeDraggabl e(anEl ement); makeChangea bl e(an El ement);
anEl ement = document.get El ementßyld('stuff'); makeDraggabl e(anEl ement);
Im vorstehenden Beispiel werden drei verschiedene Elemente der Benutzerschnittstelle
so geändert, dass sie sich ziehen, skalieren und drehen lassen; das vierte kann nur ge
zogen werden. Beachten Sie, dass zunächst eine Referenz auf das Schnittstellenelement
abgefragt und der jewei ligen Funktion bzw. den Funktionen der API übergeben wird. Das
genügt, um Ihre Benutzerschnittstellenelemente zu aktivieren.
Die bisher gezeigten banalen Umsetzungen von Drag&Drop, Skalierung und Drehung
in diesem Abschnitt laufen unabhängig voneinander ab. Wie Sie sehen, läuft das vorste
hende Beispiel darauf hinaus, dass sie in der Lage sein sollen, zusammenzuwirken. Dazu
müssen Sie ggf. die Auswirkungen kennen, die die anderen Aktionen auf das Element
gehabt haben. Die erwähnte Änderung beginnt m it den Funktionen makeDraggable
und ma keC hangeab l e.
Die erste ist fü r die Einricht ung und Verwa ltung der ontouchsta rt-Ereignislistener und
aller Befehle zuständig, die für die Behandlung nach dem Ereignis gesendet wurden.
92
Ein Modul für Drag&Drop, Skalierung und Drehung
function makeDraggab l e(anElement, startDragCmd, d ragCmd, dropCmd ){
anElement .ontouchstart = pr epa reDrag; anElement . isDraggab l e = true; if(startDragCmd){
anEl ement . startDragCmd = startDragCmd:
if(dragCmd) { anEl ement .dragCmd = dragCmd:
if(d r opCmd) { anEl ement .dropCmd = dropCmd:
Beachten Sie, dass das Attribut i sOraggabl e des Elements auf t rue gesetzt ist. Dies ist die
erste Information, die gespeichert w urde, um die Zusammenarbeit der beiden Funktionen
zu ermöglichen. Beachten Sie außerdem, dass in dieser Funktion nur ein Berührungslistener
gesetzt wird, ontouch sta rt. Wenn ein Element skal iert oder gedreht wird, sollen Berührun
gen nämlich ignoriert werden; weiter hinten in diesem Abschnitt erfahren Sie mehr dazu.
Die Funktion ma keCha ngea b l eist ähn lich. Sie legt die Gestenl istener fest, setzt das Attri
but i s Cha ngea b l e auf t rue und speichert Befehle nach dem Ereignis zur späteren Ver
wendung. Anders als die Funkt ion ma keDraggab l e legt sie Gestenlistenerfest, weil beim
Auslösen von Berührungsereignissen wegen der Einzelberührungen beim Ziehen keine
Gestenereignisse ausgelöst werden. Ist ein Element ziehbar und w ird es gezogen, werden
Berührungsereignisse ausgelöst und behandelt. Ist ein Element änderbar und erfolgt eine
Geste, werden sowohl Berührungs- als auch Gestenereignisse ausgelöst, die Berührungs
ereignisse jedoch ignoriert und die Gestenereignisse behandelt .
function ma keChangeabl e(an El ement, startChangeCmd, changeCmd, doneChangeCmd ){
an El ement.ongesturestart = prepareGesture; an El ement.ongesturec hange = change l t; an El ement.ongestureend = gestureDone; an El ement. i sChangeab l e = true; an El ement.oldRotation = 0; an El ement.oldScal e = 1 : an El ement.startChangeCmd = startChangeCmd: an El ement.changeCmd = changeCmd: an El ement.doneChangeCmd = doneChangeCmd;
93
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
in der Methode makeChangeabl ewerden zwei weitere Informationen initia lisiert, näm
lich die Akkumulatoren o l dSca l e und o l d Rotat ion fü r Ska lierung und Drehung.
in der Beispielanwendung für Gesten nimmt das Element bei jeder Skalierung und Dre
hung sofort w ieder seine Originalgröße an, weil keine automatische Speicherungfrüherer
Skalierungen zur Verfügung steht. Das Attribut o l dSca l e soll dieses Problem beheben.
Das Attribut o l dSca l e wird mit 1 initialisiert, weil Skalierung ein Mult iplikator für die
Höhe und Breite eines Elements ist (siehe weiter hinten in diesem Abschn itt). Liegt der
Skalierungsfaktor zwischen o einsch ließlich und 1 aussch ließl ich, wird das Element kleiner.
Beträgt er 1, bleibt es unverändert, bei allen anderen Werten wird es größer.
Wenn ein Element bereits skaliert wurde, muss der Ska lierungsfaktor mit dem neuen kom
biniert werden, um auf die korrekte Größe zu kommen. Wurde das Element beim ersten
Mal beispielsweise doppelt so groß, w ird der Wert von o l dSca l e auf2 gesetzt. Wenn der
Benutzer das Element auf go Prozent seiner Größe zusammendrückt, lautet der aktuel le
Ska lierungswert 2 * o.g, was 1.8 ergibt. Wenn der Wert nicht in o l dSca l e festgehalten
wäre, würde er sofort auf o.g gesetzt, was der Benutzer nicht wollte.
Weiter oben wurde die Funktion prepa reDrag dem on t ouc hsta rt-Ereignislistener
zugeordnet. Wie der folgende Code zeigt, enthä lt sie einige interessante Dinge. Das erste
ist die Speicherung eines Arrays mit Touch-Objekten, w ie sie weiter vorn in diesem Ab
schnitt beschrieben wurden, damit die Listenerfunktionen der Gestenereignisse Zugriff
auf die berührungsspezifischen Informationen bekommen. Berührungsereignisse müs
sen zum Beispiel mögl icherweise erfahren, wie viele Berührungen das Gestenereignis
auslösen, was sie nicht aus den Ereignissen entnehmen können, die den Gestenlistenern
übergeben wurden.
1 function prepareDrag(event ){ 2 st opDefaul t (event ) ; 3 t his. t ouches = event .targetTouches; 4 var se l f = th is ; 5 t his. t imeüut = setTimeout(funct ion (){ 6 if(self .changing ){ 7 8
return ;
9 se l f .draggi ng = t rue; 10 se l f . on t ouchmove = dragl t; 11 se l f . on t ouchend = dragDone ; 12 se l f . offse t X = event.targetTouches [ O] .cl i ent X; 13 se l f . offse tY = event.targetTouches [ O] .cl i ent Y; 14 se l f . ol dZindex = self .sty l e . z l ndex;
94
Ein Modul für Drag&Drop, Skalierung und Drehung
15 sel f . sty l e.z l ndex = 50: 16 i f (se l f . sta r tDragCmd ){ 17 va r params = new Array() ; 18 pa r ams.push (event) ; 19 pa r ams .push (se l f ) ; 20 handl eRequest ( sel f .s t artDragCmd . params ) ; 21 } 22 }. 75 ) ; 23 }
Ein weiterer interessanter Punkt im vorstehenden Code erscheint in Zei le 5· Anstatt die
Ausgangsposition der Berührung sofort als Attribute off setX und offset Y des zu zie
henden Elements zu speichern, wird ein Timer benutzt, um das Setzen dieser und anderer
Werte zu verschieben. Dies geschieht, wei l möglicherweise als Reaktion auf eine Geste des
Benutzers die Funktion prepa reDragaufgerufen wurde.
Es wurden Berührungsereignisse ausgelöst, wei l vor dem Auslösen von Gestenereignissen
immer Gesten stattfinden. Ist das an prepa reDrag übergebene Ereignis tatsäch lich das
Ergebnis einer Geste, brauchen die Ereignisl istener ontouchmove und ontouc hend nicht
gesetzt zu werden oder werden aufgerufen, wenn sich die Geste ändert und beendet wi rd.
Würden die Listener aufgerufen, dann w ürden sie Ziehverhalten ausführen und bewirken,
dass das Gestenverhalten nicht f unkt ioniert.
Der erstellte Timer m uss eine ausreichende Verzögerung vorsehen, damit die Gesten
listener-Funktion pr epa reGe sture aufgerufen werden kann, weil diese das Attribut
chang i ng des zu ändernden Elements aktual isiert.
Zei le 22 legt eine Verzögerung von 75 Millisekunden fest. Das reicht aus, um den Gesten
listener aufzu rufen und bei einer Geste auszuführen, ist aber ku rz genug, um den Benut
zer nicht zu ärgern, fa lls es sich um einen Ziehvorgang handelt. Ist die Verzögerung zu
lang, kann der Benutzer ohne Weiteres den Finger vom Element nehmen, bevor es sich
bewegt. Der letzte interessante Punkt ist das Füllen eines Arrays mit dem Namen pa rams
und der Aufrufvon hand l eRequest.
Der Aufruf der Funktion handl eReques t in Zeile 20 gibt Ihnen die Möglichkeit, Callout
Funktionen zu erstellen, die jedes Mal ausgeführt werden, wenn ein Berührungsereignis
ein Ziehvorgang ist. Sie werden mit hilfe von mapCommandTo* -Funktionen in der Zuordnungsdatei definiert (siehe Kapitel 2). Sie können eine beliebige Anzah l von Geschäfts- und
Ansichtssteuerfunktionen aufrufen, wenn ein Ziehvorgang gestartet wi rd. Möglicherweise
wollen Sie damit zum Beispiel das Element aus dem übergeordneten Element entfernen,
seine Hintergrundfarbe oder seine Umrandungen ändern oder noch etwas anderes t un.
95
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
Da nicht bekannt ist, ob oder wie Sie diese Callout-Funktionen benutzen, enthält das Array
pa ram s, das übergeben wird, einige Informationen. Wie im vorstehenden Code zu sehen,
handelt es sich um das gezogene und das ziehende Element. Es ist nicht bekannt, ob Sie
Callout-Funktionen erstellen, in denen Sie sie möglicherweise benötigen, aber der Ein
fachheit halber wurden sie hinzugefügt.
Wenn der Benutzer seinen Finger über das Display bewegt, wird w iederholt der on touc h
Ereignislistener d r ag I t aufgerufen. Diese Funktion dient wie die Funktion d ra g in der Bei
spielanwendung D r a g dazu, das Element entsprechend der Fingerbewegung des Benutzers
zu verschieben. Sie sehen hier jedoch die Anwendung der zuvor in den Gestenlistener-Funk
tionen und in prepar eDrag gespeicherten Daten.
Da sowohl zum Ziehen als auch zum Ablegen eine Transformation verwendet wird, muss
bei einem Ziehvorgang zusätzlich zur Versch iebung das vorherige Drehen und Skalieren be
rücksichtigt werden, wei l das Attri but webK i tT ra ns f orm des Sti ls bei jeder Verwendung
zurückgesetzt wird. Fehlen Dreh- und Skalierungsdaten im Transformationsstring, nimmt
das Element seine ursprüngliche Größe und Ausrichtung an, sobald es gezogen w ird.
Ein Transformationsstring, der in seiner Gesamtheit zu einer Versch iebung, einer Drehung
und einer Skalierung f ührt, enthä lt mehrere Funktionen:
" transl ate ( - l px , Spx) rot ateZ ( 2ldeg) sca l e ( 0.9 ) "
Diese Codezei le versch iebt das Element um 1 Pixel nach links und 5 Pixel nach unten. Ansch ließend dreht sie es um seine z-Achse. Sch ließlich verkleinert sie es auf go Prozent
seiner Origina lgröße.
Die Reihenfolge der Funktionsbeschreibungen ist von Bedeutung. Steht die Drehung im
String links von der Versch iebung, erfolgt sie zuerst , und die Versch iebung fi ndet im Win
kel zu r x- und y-Achse anstatt an diesen ent lang statt. Das wäre fehlerhaftes Drag&Drop
Verha lten, weil sich das gezogene Element im Winkel zu r Fingerbewegung des Benutzers
bewegt anstatt mit dieser.
Den Code, der den String für das Modul zusammenset zt, fi nden Sie in Zeile 13 bis 25. Die
Zeilen enthalten die Verkettung eines Tei lstrings, der zu einem String hinzugefügt wird,
welcher die Funktionsdeklaration für die Verschiebu ng enthält.
1 f unct ion d rag l t ( event) { 2 stopDe f aul t ( event ) ; 3 4 5 6
96
th i s. x th i s. y
event.ta rgetTouches [O].cl i ent X - this. offsetX; event.ta rgetTouches [O].cl i ent Y - this. offsetY;
Ein Modul für Drag&Drop, Skalierung und Drehung
7 i f ( this . lastX I I this . lastY ) { 8 this.x += t his .lastX; 9 this .y += t his .lastY ; 10
this .sty le .webkitTransfo r mOr i gi nX this.style .webkitTransfo r mOr i gi nY var modStringFragment = i f( this. isChangea ble ){
if(this.rotation){ modStringFragment +=
I 50% I; I 50% I ;
11 12 13 14 15 16 17 18
I rotateZ( 1 +this .ol dRotat ion+ldeg) 1:
19 20 21 22 23 24 25 26
if(this .ol dScale){ modStr i ngFragment +=
I sca l e( 1 +th i s .ol dSca l e+ l ) l;
var modString l trans l ate(, + t his . x + ,px , • + t his .y + ,px) l+modStr i ngFragment ;
27 this . sty l e .webkitTransfo r m = modStr ing ; 28 i f(thi s.dragCmd){ 29 var params = new Array() ; 30 pa rams . pus h(even t ) ; 31 pa rams . pus h(this ) ; 32 handl eRequest(t his .dragCmd , pa rams ) ; 33 34
EtwasBedeutsamesgeschiehtauch inZeile11und12.DieAttributewebk i tTrans fo r mO r i gi nX
und web k i tTra n s fo r mO r i g i nY werden auf ihre Standardwerte gesetzt, was erforderlich
ist, wenn Drehung oder Ska lierung vorgesehen ist, wie Sie weiter hinten in diesem Abschnitt
sehen. Erfolgt es nicht, dann hüpft das Element zu Beginn des Ziehens, und der Finger des Benutzers befindet sich nicht am selben Punkt des Elements wie ursprünglich.
Wenn der Benutzer einen Finger vom Display des Geräts nimmt, wi rd ein ontouchend
Ereignis ausgelöst und die Listener-Funktion drag Done aufgerufen. Der Zweck dieser
Funkt ion aus der Datei QCUt i l i t i es . j s, die Sie im folgenden Code sehen, besteht darin,
einige Attribute des Elements auf die Originalwerte zurückzusetzen und andere Daten zur
späteren Verwendung zu speichern.
97
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
f unct i on dragDone( event){ t his .dragg i ng = fa l se ; t his .on t ouchmove =null; t his . on t ouchend =nul l: t his . l astX = t his . x : t his . l ast Y = th is .y ; t his . st y l e .z l ndex = t his .ol dZ index ;
if ( t hi s .dropCmd){ va r params = new Ar r ay() ; params .push( even t ) ; params .push( th i s ) ; handl eReques t (t his . dropCmd , params) ;
ln dieser Funktion werden der ontouc hmove- und der ontouchend-Listener auf ihren
Leerzustand zurückgesetzt, um die Gestenbehandlung nicht zu stören, wie bereits erör
tert wurde. Der aktuelle x- und y-Wert des Elements w ird gespeichert und, fal ls vorhan
den, ein Befehl ausgeführt .
Nachdem Sie den vollständigen Ablauf der ausgefeilten Drag&Drop-Methoden gesehen
haben, ist die entsprechende Gestenhandhabung besser verständlich. Genauso, wie sich die
Gestenbehandlung auf den fü r Drag&Drop erforderlichen Code auswi rken kann, kann auch
die Drag&Drop-Handhabung Einfluss auf den Code zum Skal ieren und Drehen haben.
Die Funktion pr epareGes t ure aus der Datei QCUtil it ies . js, die Sie im folgenden
Code sehen, ist einfacher als die weiter vorn in diesem Abschnitt erörterte Funktion
p repa r eDrag. Sie setzt einige Attribute, braucht aber nicht w ie die andere Vorbereitungs
funktion f ür eine Verzögerung zu sorgen, was bereits erläutert wurde.
f unct ion pr epa reGes t ure(event) { stopDefau l t(even t ) ;
98
t his . changi ng = t rue ; t his . ol dZi ndex = t hi s . styl e .z lndex ; t his . st y l e . z l ndex = 50 ;
if (thi s . startChangeCmd ){ var pa r ams = new Array() ; params . push(even t ) ;
Ein Modul für Drag&Drop, Skalierung und Drehung
params .push(this); handleRequest( this .sta r tChan geCmd . params ) ;
Wie alle Behandlungsfunktionen für Gestenereignisse weist auch diese das Framework
an, einen Befehl durch Aufrufen der Funktion hand l eReq uest zu handhaben. Sie können
eine beliebige Anzah l von Callout-Funktionen ausführen, nachdem ein Gestenereignis
listenerfertig ist. ln Kapitel2 wird erörtert, wie Sie Funktionen Befehle zuordnen.
Wenn der Benutzer seinen Finger über das Display bewegt, wird wiederholt ein
onges t ur echange-Ereignis ausgelöst, was zum Aufruf der Funktion cha ngelt aus der
Datei QCUt i l i t i es. j s führt, die Sie im folgenden Code sehen. Sie istfür die Skalierung und
Drehung des Elementsanhand der Interaktion des Benutzers mit dem Gerät zuständig.
" rota t eZC2l deg) sca l e(0.9) t rans l ate( -lpx , Spx) "
Beachten Sie, dass Fingergesten auf zwei oder mehr versch iedenen Elementen möglich
sind. Dabei handelt es sich normalerweise um ein Versehen des Benutzers, weshalb Zeile
5 bis 8 die Reaktion der Elemente bei Berührung verhindert.
Außerdem kann der Benutzer einen Pinch machen, was dazu führen kann, dass ein Element
für zwei Finger zu klein wird. Wäre dies zulässig, könnte der Benutzer die Größe des Ele
ments nicht mehr ändern, was weitere Modifizierungen verhinderte. Die Zei len 14 bis 19
sorgen dafür, dass der Benutzer ein Element nicht versehentlich zu klein zum Vergrößern
machen kann.
Wie bereits erörtert, ist die Reihenfolge der Funktionsdeklarationen im Transformations
string von Bedeutung. Um ein Element erfolgreich zu drehen und zu skalieren, muss die
Verschiebung erfolgen, aber am Ende des Strings deklariert werden.
Erfolgt die Verschiebung zuerst, wenn der Benutzer versucht, ein Element zu drehen, wür
de das Element während der Drehung allmählich verschoben. Ist keine Verschiebung ent
halten, dreht sich das Element um seine ursprüngliche linke obere Ecke, wie es in der ihm zugewiesenen CSS-Kiasse defin iert ist. Beide Verhaltensweisen sind nicht akzeptabel.
1 function changelt(event){ 2 stopDefa ul t(event); 3 //der Benutzer hat mögl icherwe ise 4 //nur einen Finger i n das Ziel gesetzt . 5 i f ( this.dragging 6 I I ( this.touches && t his .touches. l ength < 2)){ 7 8
return :
99
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
9 10 thi s . rotat ion = event . rota t i on : 11 var rota t ionVa l ue = this . ro t at i on + thi s .ol dRotation : 12 var sca l eVa l ue = event . sca l e * th is . ol dSca l e: 13 / /es darf ni cht zu kl ein für zwei Berührungen werden 14 if( t his.offse t Wi dth * sca l eVa l ue < 150 ){ 15 sca l eVa l ue = 150/this.offsetWidt h: 16 17 el se if( this . off setHei ght * scal eVal ue < 150){ 18 sca l eVa l ue = 150/this .offset Hei ght : 19 20 thi s . scal e = sca l eVa l ue ; 21 22 var modSt ring = lrotateZ( ,+rota t ionVa l ue+ 23 ,deg) sca l e( l+scal eVa l ue+l ) I; 24 if( t his . l astX I I th is . l astY){ 25 modSt ring += I trans l at e( , + t his . l astX + ,px, . 26 + th is . l astY + ,px) l: 27 //den Drehpunkt aktual isieren 28 thi s .xCen t erOffset =50 29 + (thi s . l as t X/this . offset Width) 30 * 100 : 31 thi s .yCen t erOffset =50 32 + (thi s . las t Y/ th i s.offset Height ) 33 * 100 : 34 35 36 37 38
39
thi s . styl e .webkitTransformOrigi nX (this . xCenterOf fset )+1 %1
:
thi s . styl e .webkitTransformOrigi nY = (this .yCenterOf fset )+1 %1
:
40 t hi s . styl e .we bki tTransform = modStr i ng ; 41 42 if( t his . changeCmd){ 43 44 45 46 47 48
100
var params = new Ar ray(); params . pus h(event ) ; params . pus h(this ) ; handl eRequest(thi s . changeCmd , params);
Ein Modul für Drag&Drop, Skalierung und Drehung
ln Zeile 22 bis 39 werden der Transformationsstring erstellt und die Werte für webki tTrans fo rmOr i gi n gesetzt, sodass die Skalierung und die Drehung auf der Grundlage des geänderten optischen Mittelpunkts des Elements stattfinden können. Die Ursprungsänderungen im vorstehenden Code haben es erforderlich gemacht, sie in derbereits erörterten Methode d ra g I t zurückzusetzen. Als Transformationsursprung dient aus
gehend vom aktuellen Abstand von der Ausgangsposition der Mittelpunkt des Elements.
Wenn der Benutzer seine Finger wegnimmt, wird ein ongestureend-Ereignis ausgelöst und der unten stehende gestureDone-Ereignishandler aufgerufen. Abgesehen von einer Ausnahme entspricht er der Methode dragDone; wie die Funktion prepa reDrag enthält er einen Timer.
1 function gestureDone(event){ 2 th is .sty l e.zlndex = this.o l dZindex; 3 II Mögl icherweise hat der Benutzer ke i ne Drehung durc hgeführt. 4 II Dann ist r ota t ion undefiniert. 5 i f ( this . rotation){ 6 this. ol dRota t ion += this.rotation; 7 } 8 II Mög l icherweise hat der Benutzer keine Ska l ierung 9 II durchgeführt . Dann ist sca l e undefin iert . 10 i f( this.sca l e){ 11 12 13
this.ol dScal e = th is . sca l e;
14 if ( this.doneChangeCmd) { 15 16 17 18 19
var params = new Array() ; pa rams . push (even t ) ; pa rams . push (this ) ; handleReques t (t his .doneChangeCmd, params ) ;
20 var sel f = this; 21 this.timeOut = setTimeout(function(){ 22 sel f .changing = fa l se; 23 } '75 ) ; 24
101
Kapitel 3 Benutzerschnittstellen für das iPhone erstellen
DieserTimer (Zeile 21 bis 23) ist aus demselben Grund vorhanden wie der in p r epa reD rag.
Beim Auslösen der ongestureend-Ereignisse sind einige Berührungsereignisse noch
unbehandelt. Wird das Attributcha nging des Elements sofort auf fa l se gesetzt (siehe Zeile 22), werden durch den Code in prepa r eDrag (siehe weiter vorne) die Ereignisliste
ner für den Ziehvorgang aktiviert.
Geschieht dies fü r eine Skalierungs- oder Drehgeste, hüpft das Element ungewollt auf
dem Display, was dem Benutzer negativ auffällt.
Drag&Drop, Skalierung und Drehung müssen zwar voneinander wissen, ihr Verhalten
muss jedoch streng getrennt werden, weil sich die Anwendung sonst verwirrend und nicht
vorhersehbar verhält. Der Code in diesem Abschn itt und in der Datei QCUt i l i t i es. j s
stellt Ihnen eine einsetzbare fertige Implementierung von Drag&Drop-, Skalierungs- und
Drehungsverha ltensweisen zur Verfügung.
3.7 ZUSAMMENFASSUNG
Aus Benutzersicht ist die Schnittstelle Ihrer Anwendung die Anwendung. Eine schlechte
Gesta ltung wie in dem abschreckenden Beispiel des Spiels DollarStash kann zum Unter
gang Ihrer Anwendung führen, bevor sie eine Chance zur Verbesserung oder Korrektur
bekommt . Wie in diesem Kapitel beschrieben, beruht eine kluge Schnittstellengesta ltung
auf drei Prinzipien:
> Überraschen Sie den Benutzer nicht. Verwenden Sie gängige Verhaltensweisen für
die Interaktion.
> Gestalten Sie die Schnittstelle intuitiv. Es sollte nicht notwendig sein, die Anleitung
zu lesen.
> Stellen Sie keine Anforderungen an Ihre Geräte, die sie nicht erfüllen können. Pro-
zessor- und Speicherressourcen sind begrenzt. Gehen Sie klug damit um.
Wenn Sie sich an diese Grundregeln und an die Schnittstellenrichtlinien von Apple halten,
stehen die Erfolgschancen Ihrer Anwendung wesentlich besser. Die Regeln mögen zwar
streng wi rken, lassen aber dennoch Raum für Kreativität, wie das Modul für Drag&Drop,
Skalierung und Drehung zeigt.
Wird es überlegt erstellt und benutzt, kann es den Eindruck des Benutzers von Ihrer An
wendung gewaltig verbessern, weil es auf der integrierten Mehrfachberührungsfähigkeit
der Geräte iPhone und iPod touchsowie den Schnittstellenrichtlinien von Apple aufbaut.
102
GPS, Beschleunigungsmessung und andere systemeigene Funktionen von OuickConnect -Das iPhone besitzt zahlreiche einzigart ige Fähigkeiten, die Sie in Ihren Anwendungen ein
setzen können, beispielsweise den Vibrat ionsalarm, das Abspielen von Systemklängen,
die Beschleunigungsmessung und die Nut zung von GPS-Ortsinformat ionen. Außerdem
können Sie in Ihrer Anwendung vorsehen, Meldungen zur Feh lerbehebung in der Xcode
Konsole auszugeben. Der Zugriff auf diese Fähigkeiten ist nicht auf Obj ective-C-Anwen
dungen beschränkt; lhreWeb-Apps erreichen Sie ausJavaScript heraus. Im ersten Abschnitt
dieses Kapitels w ird erklärt, wie Sie sie und andere syst emeigene iPhone-Funktionen mit
hilfe der JavaScript-API von QuickConnect iPhone benutzen. Der zweite Abschnitt zeigt den
Obj ect ive-C-Code, der der JavaScript-Bibliothek von QuickConnectiPhone zugrunde liegt.
Kapitel 4 Systemeigene Funktionen von QuickConnect
4.1 GERÄTEAKTIVIERUNG IN JAVASCRIPT
Das iPhone ist ein Gerät, das wesentliche Veränderungen bringt. Einer der Gründe da
für ist der Umstand, dass Autoren von Anwendungen auf Hardware wie die Beschleuni
gungsmessung zugreifen können. Mit diesen systemeigenen iPhone-Funktionen lassen
sich innovative Anwendungen erstellen. Die Entscheidung, wie Ihre Anwendung auf eine
Änderung der Besch leunigung oder der GPS-Ortsdaten reagiert, liegt in Ihrer Hand. Sie
entscheiden auch, wann das Mobi ltelefon vibriert oder eine Audiodatei abspielt.
Die QuickConnectiPhone-Datei com . j s enthält eine Funktion, mit der Sie auf einfache,
leicht verwendbare Weise auf dieses Verhalten zugreifen können. Es handelt sich um die
Funktion ma keCa 11, mit der Ihre Anwendung Anforderungen an das Mobiltelefon stellt.
Sie benötigt zwei Parameter: Der erste ist ein Befehlsst ring, der zweite eine Stringversion
aller Paramet er, die zur Ausführung des Befehls erforderlich sind. ln Tabelle 4.1 sind al le
Standardbefehle mit den erforderlichen Parametern und der Verhaltensweise des iPhones
bei Ausf ührung des Befehls aufgeführt .
Befehlsstring Meldungsstring Verhalten I
1ogMessage Al le im X-Terminal zu Die Meldung erscheint im
prot okol lierenden Informationen Xcode-Terminal, wenn der Code
ausgef ührt w ird.
rec Ein JSON-String eines JavaScript- Es wird eine caf -Audiodatei
Arrays mit dem Namen der zu m it dem im String definierten
erstellenden Audiodatei als erstes Namen angelegt .
Element. Das zweite Element des
Arrays laut et j e nachdem, ob Sie
die Aufzeichnung von Aud iodaten
starten oder stoppen wol len,
s ta r t oder s top.
p1ay Ein JSON-String eines JavaScript- Wenn die Audiodat ei
Arrays mit dem Namen der vorhanden ist, w ird sie über die
abzuspielenden Audiodatei Lautsprecher des Geräts oder
als erstes Element . Das zweite den Kopfhörer abgespielt .
Element des Arrays lautet je
nachdem, ob Sie das Abspielen der
Audiodatei starten oder st oppen
wollen, sta r toder stop.
104
Geräteaktivierung in JavaScript
l oc Keine Die Ortsbestimmung des
Geräts wird ausgelöst,
und es werden Daten über
geografische Breite, Länge
und Höhe an die JavaScript-
Anwendung übermittelt.
pl aySound -1 Das Gerät vibriert.
pl aySound 0 Die Audiodatei l aser. wav
wird abgespielt.
showDate DateTime Die systemeigene Datums- und
Uhrzeitabfrage wird abgespielt.
showDate Date Die systemeigene
Dat umsabfrage wird
abgespielt.
Tabelle 4 .1: Die Befehls-AP/für MakeCa/1
Die Beispielanwendung Dev i ceCa ta l og enthä lt eine Schaltfläche VI BRATE, die das Mobil
telefon beimAnklicken vibrieren lässt. Die onc l i ck-Ereignishandlerfunktion der Scha lt
fläche heißt v i bra teDevi ce; Sie sehen sie im folgenden Beispiel. Sie ruft die Funkt ion
ma keCa l l auf und übergibt ihr den Befehl p l aySound mit dem Zusatzparameter - 1. Der Befehl veranlasst, dass das Mobi ltelefon vibriert. Der Befehl p l aySound wi rd verwendet,
wei l das iPhone Vibrationen und ku rze Systemklänge als Klänge behandelt.
function vibrateDevice(event) {
//der I ndi kator - 1 veran l asst, dass das Te l efon vibriert makeCal l ( " pl aySound ", - 1) ;
Da Vibration und Systemklänge gleich behandelt werden, läuft das Abspielen eines Sys
temklangs fast genauso ab. Der onc l i ck-Ereignishand ler der Schaltfläche SouND heißt
p l aySound. Wie Sie im folgenden Code sehen, besteht der einzige Unterschied zwischen
ihm und v i brateDevi ce im zweiten Parameter.
Wird als zweiter Parameter 0 übergeben, wird die Datei l aser. wav aus den Ressourcen
des Projekts Dev i ceCa ta l og als Systemklang wiedergegeben. Audiodateien f ür System
klänge dürfen maximal f ünf Sekunden lang sein, damit sie als Klang abgespielt werden
105
Kapitel4 Systemeigene Funktionen von QuickConnect
können. Längere Dateien werden mithilfe des Befehls p l ay wiedergegeben, der weiter
hinten in diesem Abschnitt behandelt wird.
function pl aySoundCevent) {
//der Indi kator 0 veranlasst, dass das Telefon den Kl ang // " laser" abspie l t makeCa llC "pl aySound", 0 ) :
Die im vorstehenden Code verwendete Funktion ma keCa ll liegt vollständig in JavaScript
vor und ist im folgenden Code zu sehen. Sie besteht aus zwei Teilen. Der erste stel lt die
Meldung in eine Warteschlange, wenn sie nicht sofort gesendet werden kann. Der zweite
sendet sie zur Behandlung an den zugrunde liegenden Objective-C-Code. Die Meldung
w ird übergeben, indem die Eigenschaft wi ndow. l ocat i on in einen nicht vorhandenen
URL, ca l l , umgewandelt w ird und die beiden Parameter der Funktion als Parameter des
URL übergeben werden.
function ma keCa l l ( command, dataString ) { var messageString = " cmd="+command+"&msg="+dataString; if( StoreMessage I I ! canSend ){
messages.push (messageString);
el se { storeMessage = true; window. l ocation = "ca l l ?"+messageString;
Diese Art, den URL zu setzen, führt dazu, dass eine Meldung mit dem URL und seinen
Parametern an eine Objective-C-Komponente gesendet wird, die zum zugrunde liegen
den QuickConnectiPhone-Framework gehört. Diese Komponente dient dazu, das Laden
der neuen Seite zu beenden und den Befehl und die Meldung, die sie erhalten hat, an
den Befehlsbehandlungscode des Framewerks zu leiten. Wie dies geschieht, können Sie in
Abschnitt 2 lesen.
Die Befehle pl aySound, l ogMessage, rec und pl ay sind unidirektional, d.h., dass die
Kommunikation von JavaScript an Objective-C gerichtet ist, ohne dass Daten zurück
erwartet werden. Die übrigen unid irektionalen Standardbefehle führen dazu, dass Daten
von den Obj ective-C-Komponenten zurück an JavaScript gesendet werden.
Die Datenübergabe zurück an JavaScript erfolgt auf zwei Arten. Ein Beispiel für die erste
bildet die Übertragung von Beschleunigungsdaten in die x-, y- und z-Koordinate durch
106
Geräteaktivierung in JavaScript
einen Aufruf der JavaScript-Funktion handl eRequest, die in Kapitel 2, »Die Modularität
von JavaScript für iPhone-Anwendungen«, beschrieben wurde. Der Aufruf verwendet den
Befeh I a c c e l sowie die von den Objective-C -Korn ponenten des Fra meworks als JavaScript
Obj ekt übergegebene x-, y- und z-Koord inate.
Die Datei ma pp i ngs. j s bewirkt, dass der Befehl a cce l der Funktion d i s p l ay Acce l e
rat i on V CF zugeordnet wird, wie Sie in der folgenden Zeile sehen:
mapCommandToVCF('accel ', displayAccel erationVCF);
Dadurch wird displ ayAccelerationVCF jedes Mal aufgerufen, wenn die Beschleuni
gungsmessung eine Bewegung feststellt. Die Funktion ist für die Behandlung der Besch leu
nigungsereignisse zuständig.ln der Beispielanwendung Dev i ceCa ta l og setzt sie einfach
die Beschleunigungswerte fü r x, y und z in ein HTML-di v-Eiement ein. Sie sollten sie so
ändern, dass sie diese Werte für Ihre Anwendung benutzt.
Die zweite Methode, Daten an JavaScript zu rückzusenden, bedient sich der JavaScript
Funkt ion hand l eJSONRequest, die weitgehend ähnlich f unktioniert wie die in Kapitel 2
beschriebene Funktion h a nd l eReques t, j edoch als zweiten Parameter einen JSON-String
erwartet. Sie stellt eine Fassade fü r h a nd l eReques t dar. Wie im folgenden Code zu sehen,
wandelt sie einfach den JSON-String, der ihr zweiter Pa rameter ist, in ein JavaScript-Obj ekt
um und übergibt den Befehl und das neue Objekt an die Methode hand l eRequest. Diese
Art der Datenübert ragung w ird als Reaktion auf eine GPS-Ortsanforderung verwendet,
die von einem Auf rufvon ma keCa l l ( " l oc") ausgeht, sowie auf die Anforderung, einen
Pickerfür Datum und Uhrzeit anzuzeigen.
function handl eJSONRequest(cmd , parametersString){ var paramsArray =nul l : if(parametersStr i ng) {
var paramsArray = JSON . parse( parametersString);
handl eRequest(cmd , paramsArray);
ln beiden Fä llen werden die Ergebnisdaten in einen JSON-String umgewandelt und an
handl eJSONRequest übergeben. Weitere Informationen über JSON finden Sie in Anhang A, »Einführung in JSON«.
Da sowohl in JavaScripta ls auch in Objective-C JSON-Bibliotheken zur Verfügung stehen,
stellt JSON eine günstige Methode dar, um komplexe Informationen zwischen zwei Spra
chen in einer Anwendung zu übermitteln. Ein einfaches Beispiel daf ür sind die onc l i c k
Handler zum Starten und Stoppen der Aufzeichnung bzw. Wiedergabe von Aud iodateien.
107
Kapitel 4 Systemeigene Funktionen von QuickConnect
Der Handler pl ay Record i ng ist typisch für alle Scha ltflächenhandler in der Benutzer
schnittstelle, die Geräteverhalten aktivieren. Wie im folgenden Beispiel gezeigt, legt er ein
JavaScript-Array an, fügt zwei Werte hinzu, konvertiert das Array in einen JSON-String und
führt danach die Funktion ma keCa l l mit dem Befeh l p l ay aus.
f unct i on pl ay Record ing( event) {
va r params = new Array ( ) ; params[ OJ = "recordedFi l e . ca f": params[l ] = " start": makeCallC "pl ay ", JSON. stri ngify(params )) ;
Um das Abspielen einer Aufzeichnung zu beenden, wi rd ebenfalls die Funktion makeCa ll
mit dem Befehl p l ay gestartet, aber als zweiter Parameter fungiert nichts ta rt, sondern
stop. Die Funktion termi natePl ay in der Dateimai n. j s setzt dieses Verhalten um.
Das Starten und Stoppen der Aufzeichnung von Audiodaten erfolgt auf dieselbe Weise
w ie pl ayRecord i ng und ter mi natePl ayi ng abgesehen davon, dass an die Stelle des
Befehls p l ay der Befehl rec t ritt. Dass die Implementierung dieser verwandten Fäh ig
keiten ähnlich aussieht, macht es Ihnen erheblich einfacher, die Verhaltensweisen in Ihre
Anwendung aufzunehmen.
iijiiijjijijj CUrrerv LOcanon: IIIIUJde: 37.331688 klnglnlclo: -122.030731 a1111Ude: o
Acceleromelef Values:
Aooio
108
~ Abbildung 4.1: Die Beispielanwendung DeviceCatalog mit der Anzeige von GPS-Daten
Geräteaktivierung in JavaScript
Wie Sie weiter vorn in diesem Abschnitt gesehen haben, setzen ein ige Verhaltensweisen
des Geräts wie die Vibration lediglich die Kommunikation vom JavaScript-Code zu den
Objective-C-Handlern voraus. Andere wie das Abfragen der aktuellen GPS-Koordinaten
oder der Ergebnisse eines Pickers benötigen die Kommunikation in beide Richtungen.
Abbildung 4.1 zeigt die Anwendung Devi ceCata log mit GPS-Daten.
Wie bei einigen der bereits untersuchten unidirektionalen Beispiele beginnt die Kommuni
kation im JavaScript-Code Ihrer Anwendung. Die Funktion getGPSLocati on in der Datei ma in. j s initiiert die Kommunikation mit der Funktion ma keCa ll. Beachten Sie, dass die
se wie in den früheren Beispielen nichts zurückgibt. Sie verwendet für die Kommunikation
mit der Objective-C-Seite der Bibliothek ein asynchrones Protokoll, selbst wenn die Kom
munikation bidi rektiona I verläuft, sodass kein Rückgabewert zur Verfügung steht.
func t ion getGPS Locat i on(event) {
document.getEl emen tßyld( ' l ocDispl ay') . innerText makeCa l l ( " l oc " );
Da die Kommunikation wie AJAX asynchron ist, muss eine Rückruffunktion erstellt und
aufgerufen werden, um die GPS-Daten zu empfangen. Im QuickConnectiPhone-Frame
work geschieht dies durch eine Zuordnung in der Zuordnungsdatei, die den Befehl s how
Loc einer Funktion zuordnet:
mapCommandToVCF( ' showloc '. displ ayLocationVCF);
in diesem Fall wird er der Ansichtssteuerfunktion d i sp l ay l ocati onVC F zugeordnet.
Diese einfache Beispielfunktion wird lediglich verwendet, um den aktuellen GPS-Ort in
einem d i V-Element auf dem Display auszugeben. Diese Werte können natürl ich auch ein
gesetzt werden, um Entfernungen zu berechnen und in einer Datenbank abzu legen oder
mit dem in Kapitel 7, » Datenzugriff über das Netzwerk«, beschriebenen Se rve rAcces s
Obj ec t an einen Server zu senden.
func t ion displ aylocat ionVCF(data, paramArray){ document.getEl emen tßyld( ' l ocDispl ay ' ).innerTex t = , l at itude: '+paramArray[OJ+ ' \n l ongitude: ' +paramArray[l]+'\nal t itude: ,+paramArray[2];
109
Kapitel 4 Systemeigene Funktionen von QuickConnect
Die Anzeige eines Pickers, beispielsweise des Standardpickers für Datum und Uhrzeit,
und anschließend der ausgewählten Ergebnisse erfolgt ähnlich wie im vorstehenden Bei
spiel. DerVorgang beginnt ebenfalls m it einem Auf ruf des Gerätebehandlungscodes aus
JavaScript heraus.ln diesem Fall ist die Funktion showDateSe l ector in der Datei mai n .
j s der Ereignishandler der Schaltfläche.
f unct ion showDateSel ector(event) {
makeCall ( "showDate", "DateTime " ) ;
Wie beim GPS-Beispiel wi rd auch hier eine Zuordnung benötigt. Sie ordnet den Befehl
s howPi c kResu l ts der Ansichtssteuerfunktion d i s p l ay Pi c kerSe l ect i onVC F zu:
mapCommandToVCF( ' showPi ckResul ts', di sp l ayPickerSe l ectionVCF) ;
Die Funktion, der der Befehl zugeordnet wi rd, f ügt die Ergebnisse der Auswah l des Benut
zers in ein einfaches d i v-Eiement ein, wie der folgende Code zeigt. Diese Daten können
natürlich aufvielfache Weise genutzt werden.
f unct i on dis pl ayPic kerSel ect ionVCF(data , pa ramArray){ document.getEl ementBy l d('pickerResul ts ' ) .innerHTML pa ramArray [ OJ :
Einige Verwendungen von ma keCa l l kommun izieren wie die f rühen Beispiele in diesem
Abschn itt unid irektiona l vom JavaScript-Code zu den Obj ective-C-Gerätehandlern, die ge
rade untersuchten dagegen bid irektional zu und von den Handlern.Außerdem ermögl icht
das Gerät die unidirektionale Kommun ikation vom Gerät zum JavaScript-Code, etwa bei
der Verwendung von Beschleunigungsmessdaten.
Der Obj ective-C-Handler für Besch leunigungsereignisse (Code siehe Abschnitt 2) ruft die
JavaScript-Funktion handl eRequest auf und übergibt ihr di rekt den Befehl acce l . Der
folgende Befehl acce l ist der Ansichtssteuerfunktion d i s p l ay Acce l era t i on VC Fzuge
ordnet.
mapCommandToVCF( ' acce l '. displ ayAcce l erat i onVCF);
Wie die anderen Ansichtssteuerfunktionen setzt auch diese die Beschleunigungswerte in ein d i v-Eiement ein.
}
f unct i on dis pl ayAcce l erationVCF(data , param) { document.getEl ementBy l d('accel Displ ay') . innerText ' x : '+pa ram. x+' \ny : '+pa ram .y+' \nz: ,+pa ram.z:
110
Geräteaktivierung in Objective-c
Ein Unterschied zwischen dieser Funktion und den anderen besteht darin, dass ihr kein
Array, sondern ein Objekt als Parameter pa ram übergeben wird.ln Abschnitt 2 wird gezeigt,
wie es aus Informationen erstellt wurde, die der Objective-C-Handler für Besch leunigungs
ereign isse übermittelt hat.
ln diesem Abschn itt haben Sie erfahren, wie Sie einige der meistverlangten iPhone-Ver
haltensweisen in Ihre auf JavaScript basierende Anwendung integrieren. Abschn itt 2 stel lt
Ihnen die Objective-C-Teile des Frameworks vor, die diese Fähigkeit unterstützen.
4.2 GERÄTEAKTIVIERUNG IN ÜBJECTIVE-(
Dieser Abschn itt setzt voraus, dass Sie mit Objective-C und seiner Verwendung zum Er
stellen von iPhone-Anwendungen vertraut sind. Sollte dies nicht der Fall sein, können
Sie The iPhone Developer's Cookbook von Erica Sadun aus dem Verlag Pearson Publishing
lesen. Fa lls Sie das QuickConnectiPhone-Framework led iglich verwenden wollen, um
JavaScript -Anwendungen f ür das iPhone zu schreiben, brauchen Sie diesen Abschnitt
nicht durchzuarbeiten.
Das iPhone mithilfe von Objective-C vibrieren zu lassen, ist eine der am einfachsten umzusetzenden Verha ltensweisen. Wenn Sie das Aud ioToolbox-Framework in die Ressourcen
Ihres Proj ekts einbinden, benöt igen Sie dazu nur die folgende eine Codezeile.
Audi oServices Pl aySystemSound(kSys t emSoundi D_Vi brate);
Die Frage lautet dann; »Wie bekomme ich die Funktion Audi oServi cesPl aySystem
Sound aufgerufen, wenn die U IWebVi ew angewiesen wird, sich mithilfe des JavaScript Befehls wi ndow . l oca t ionneu zu laden?«
Der QuickConnectViewController implementiert die Delegatmethode shoul dSt a r tload
WithRequest. Da der Delegat der eingebetteten UIWebView, aWebVi ew, als QuickCon
nectViewCont roller best immt ist, w ird diese Methode immer dann aufgerufen, wenn die
eingebettete UIWebView ihren Ort ändern soll. Der folgende Code und Zeile 133 der Datei
Qu i ckConnect Vi ewCont roll er zeigen, wie dieser Delegat gesetzt wird.
[aWebView setDel ega t e : se l f ] ;
Das Grundverhalten der Funkt ion s houl dSta rt Loa dWit h Req ues t ist unkompliziert.
Sie dient zum Schreiben von Code, der entscheidet, ob die angeforderte neue Seite tat
säch lich geladen werden soll. Das QuickConnectiPhone-Framework nutzt die Entschei
dungsfähigkeit, um das Laden von Seiten durch Anforderungen der in Abschnitt 1 gezeig
ten JavaScript -Aufrufe abzu lehnen und anderen Obj ective-C-Code auszuführen.
111
Kapitel 4 Systemeigene Funktionen von QuickConnect
Die Methode shoul dSta r tloadWi t hReques t bietet einige Parameter:
> curWebVi ew - Die UIWebView, die Ihre JavaScript-Anwendung enthält.
> request - Ein Objekt vom Typ NSURLRequest,das unter anderem den neuen URL
enthält.
> na v i ga t ionType - Einen UIWebViewNavigationType, der eingesetzt werden
kann, um zu ermitteln, ob die Anforderung auf die Auswahl eines links durch den
Benutzer oder auf etwas anderes zurückgeht.
- CBOO L)webView : CUIWebView *)curWebV i ew shou l dStartloadWithRequest:CNSURLRequest *)reques t nav i gat i onType : CUIWebViewNavigationType)navi gationType
Der von der JavaScript-Funkt ion ma keCa l l erstellte URL, der die Vibration des Geräts auslöst, nämlich ca ll ?cmd=pl aySound&msg=-1, ist im Objekt request entha lten und
lässt sich problemlos als String abfragen, indem Sie ihm die Meldung URL übergeben. Die
se gibt ein Obj ekt vom Typ NSU R L zurück, das dann die Meldung abso l uteStri ng erhält.
Auf diese Weise gewinnen Sie einen Zeigervom Typ NSSt ring auf den URL, der im folgen
den Code als ur l auftaucht. Er lässt sich mithilfe von ? als Tei lungstrennzeichen in ein
Array unterteilen, das Zeiger vom Typ NSSt ring ent hält .
NSString *u r l = [[ reques t URLJ abso l uteString]; NSArray *ur l Array = [ur l componen tsSeparatedßyStr ing :@" ?" J :
Das Array url Array enthält zwei Elemente. Das erste ist der ca l l -Teil des URL, das zwei
te der Betehisstring cmd=p l aySound&msg=-1. Um zu ermitteln, mit welchem Befehl ge
arbeitet werden soll und welche Parameter erforderlich sind, in diesem Fal l mi tl, muss
der Betehisstring weiter zerlegt werden. Dazu w ird er beim Zeichen & geteilt, wodurch ein
weiteres Array mit dem Namen url Pa ramsAr ray entsteht.
NSString *commandSt r i ng = [ url Array objectAt l ndex:l]; NSArray *ur l ParamsArray = [ commandStr i ng componentsSeparatedByString :@"&" J: //der Befehl ist der ers t e Parameter i m URL NSString *cmd = [[ [ ur l ParamsArray objectAtlndex :OJ componentsSeparatedByString :@"= " J objectAtlndex :l]:
ln diesem Fal l, der Anforderung der Vibration des Geräts, ist cmd=p l aySound das erste
Element des Arrays ur l Pa rams Ar ray, msg=l das zweite. Durch Untertei lung der Array
elemente lassen sich also der auszuführende Befehl und seine Pa rameter gewinnen. Das Zeichen = stel lt dabei das Trennzeichen dar.
112
Geräteaktivierung in Objective-c
ln Zeile 1 bis 3 des folgenden Beispiels w ird der Parameter abgefragt, der als der mit dem
Schlüssel msg verknüpfte Wert im URL als String pa rameterArrayStr i ng mit dem Typ
NSSt ring gesendet wurde. Da der JavaScript-Code, der den URL erstellt hat, alle Elemente
dieses Werts in JSON konvertiert, ist NSStri ng ein Objekt, das ins JSON-Format umge
wandelt wurde. Dies sch ließt Zah len wie das aktuelle Beispiel und Strings, Arrays oder an
dere Parameter ein, die aus dem JavaScript-Code stammen. Enthalten die Daten Leer- oder
andere Sonderzeichen, versieht UIWebView sie als Bestandteil des URL mit Escape-Codes.
Deshalb werden Zeile 6 bis 8 im folgenden Code benötigt, die die Maskierung der Sonder
zeichen im JSON-String beseitigen.
1 NSStr i ng *parameterArraySt ring = [[[url ParamsArray 2 objectAtlndex:1 ] componentsSeparatedßyString:@"="J
3 objectAt l ndex:1 ] : 4 //Kodierung bese i tigen , mit denen UI We bVi ew die 5 //URL- Zeichen maskiert hat. 6 paramet erArraySt r i ng = [ parameterArrayString 7 stringByRepl acingPercen t EscapesUsi ngEncoding: 8 NSASCIISt r i ngEncoding]; 9 SBJ SON *genera t or = [ SBJSON al l oc ]; 10 NSError *error: 11 paramsToPass = [[ NSMuta bl eArray al loc ] 12 initWit hArray: [ generator 13 objectWi thSt r i ng: parameterArrayString 14 error :&error ] J : 15 if([paramsToPass count] == 0){ 16 //wenn kein Array mi t Da t en gesendet wurde, muss es ei n 17 //String gewesen sein , der al s einz i ger Parameter 18 //gesende t wurde . 19 [ paramsToPass addObject: paramet erArraySt r i ng ]; 20 21 [ genera t or re l ease ] ;
ln Zeile 9 bis 14 im vorstehenden Code erfolgt die Konvert ierung des JSON-St rings
pa rameterArrayS t ri ng in ein systemeigenes Obj ective-C-Array vom Typ NSArray. Zei
le 9 weist ein SBJSON-Generatorobj ekt zu, dem anschließend die Meldung obj ectWi t h
St r i ng gesendet w ird, die in derfolgenden Codezeile steht:
- Ci d)objectWi t hStr ing:CNSSt ring*)jsonrep error:CNSError**)error:
Dieser mehrteiligen Meldung werden ein JSON-String, hier paramet erArrayStr i ng, und
ein Zeiger vom Typ NSE rror, also er ror, übergeben. Der Zeiger er ro r wi rd für den Fall zu
gewiesen, dass bei der Konvert ierung ein Feh ler auftritt. Geschieht nichts, ist er n i l .
113
Kapitel 4 Systemeigene Funktionen von QuickConnect
Der Rückgabewert dieser Meidung ist in diesem Fa ll die Zahl -1. Wird ein JavaScript-Array
in einen String umgewandelt, wird es zum Zeiger vom Typ NSAr ra y, ein JavaScript-String
zum Zeiger vom Typ NSStr i ng. Wenn ein benutzerdefiniertes JavaScript-Objekt über
geben wird, ist das Rückgabeobjekt ein Zeiger vom Typ NSDi ct i ona r y .
Nach der Abf rage des Befehls und der Parameter, die für ihn benötigt werden, kann für die
eigentl iche Berechnung eine i f- oder case-Anweisung verwendet werden. Eine solche
Gruppe von Bedingungen ist jedoch nicht optimal, weil sie bei jedem Hinzufügen oder
Entfernen eines Befehls geändert werden müssen. ln Kapitel 2 wird dieses Problem im
JavaScri pt-Teil der Qu ickCon neeti Phone-Architektu r durch Implementiereneiner Frontcon
troller-Funktion mit dem Namen hand l eRequest gelöst, die Aufrufe von Implementie
rungen der Anwendungscontroller enthält. Da hier dasselbe Problem vorliegt, sollte eine
Objective-C-Version von hand l eRequest es beheben. Abschnitt 3 behandelt die Imple
mentierung der Front- und Anwendungscontroller in Objeetive-C. Die folgende Codezei le
fragt eine Instanz des QuickConnect-Objekts ab und übergibt ihr die mehrtei lige Meldung ha nd l eReq ues tWi t h Paramete r s. lnnerhalb der Delegatmethode s hou l dSta r tload
Wi t h Reques t ist keine weitere Berechnung erforderlich.
[ [Quic kConnect getlnstance ] handl eRequest:cmd wi t hParameters:paramsToPass];
Da die Meldung hand l eRequest der QuickConnectiPhone-Objekte verwendet wird,
muss es eine Möglichkeit geben, den Befehl der erforderl ichen Funktionalität zuzuord
nen, wie es in Kapitel 2 mit JavaScript gezeigt w urde. Das QCCommandMa ppi ngs-Objekt
aus den Dateien QCCommandMa ppi ngs. m und . h der Gruppe QCOb j C enthält sämtliche
Zuordnungen fü r Geschäfts- und Ansichtssteuerobjekte (Business Control Obj ects, BCO,
bzw. View Control Objects, VCO) für dieses Beispiel.
Derfolgende Code ist die Methode mapCommands des QCCommandMappi ngs-Obj ekts, das
beim Start der Anwendung aufgerufen w ird. Ihm wi rd die Implementierung eines Anwen
dungscontrollers übergeben, die zum Erstellen der Zuordnungen von Befehlen zu Funk
tionalität verwendet wird. Eine Erläuterung des Codes für die Meldung mapCommand
ToVCO und den Aufrufvon mapCommands fi nden Sie in Abschn itt 3.
1 + Cvo i d ) mapCommands:CQCAppControl l er* )aCont r oll er{ 2 [aControl l er mapCommandToVCO:@" l ogMessa ge"
withFunction:@" LoggingVCO" J : 3 [aControl l er mapCommandToVCO:@" pl ay Sound"
withFunction:@" Pl aySoundVCO"J: 4 [aControl l er mapCommandToBCO:@" l oc "
withFunction:@" Locat ionBCO" J :
114
Geräteaktivierung in Objective-c
5 [aContro l l er mapCommandToVCO :@"send l oc"
with Function:@" LocationVCO " J: 6 [aContro l l er mapCommandToVCO :@"showDate"
withFunct ion :@"DatePickerVCO "J : 7 [aContro l l er mapCommandToVCO :@"sendPickResu l ts "
withFunct ion :@"PickResul tsVCO" J: 8 [aContro l l er mapCommandToVCO :@"pl ay "
withFunct ion :@"Pl ayAud i oVCO " J: 9 [aContro l l er mapCommandToVCO :@"rec" withFunction:
@"RecordAudioVCO " J : 10 }
Zeile 3 des vorstehenden Codes bezieht sich auf das aktuelle Beispiel der Vibration des
Geräts. Wie in diesem Abschnitt bereits gezeigt, lautet dervom JavaScript -Teil der Anwen
dung erhaltene Befeh l p l aySound. lndem dieser Befeh l als erster Parameter der Meldung
ma pComma ndToVCO und Pl aySoundVCO als Parameter fü r den zweiten Teil, wit h Func
t i on, gesendet werden, entsteht eine Verknüpfung, die den Anwendungscontrol ler ver
an lasst, eine doCommand-Meldung mit dem Parameter - 1 an die Klasse Pl aySoundVCO
zu senden. Wie Sie sehen, werden hier al le anderen Befeh le des Beispiels Dev i ceCa ta l og
zugeordnet, die vom Java Script -Code gesendet werden.
Der Code fü r die Funktion Pl aySoundVCO, der der Befeh l pl aySound zugeordnet ist,
steht in den Dateien Pl aySoundVCO . m und Pl aySoundVCO. h. Die Methode doCommand
enthä lt das gesamte Verhalten des Objekts.
Um einen Systemklang abzuspielen, muss ein vordefinierter Klang verwendet werden. Bis
her gibt es nur einen, die Vibration. Alternativ kann ein Systemklang aus einer Klangdatei
erstellt werden. Beispiele für beide Verha ltensweisen bietet die Methode doComma nd der
Klasse Pl aySoundVCO.
1 + (i d ) doCommand : (NSArray*) parameters{ 2 SystemSoundiD aSound =
3 [((NSNumbe r* ) [ parameters objectAtlndex:1 ] ) i ntVa l ue]; 4 i f ( aSound == - 1){ 5 aSound = kSystemSoundiD_Vib rate;
6 7 el se{
8 NSString *soundFi l e = 9 [[NSBundl e mainßundl e] pa th For Resource :@" l aser "
10 ofTy pe :@"wav " J : 11 NSURL *ur l = [ NSURL fi l eURLWithPath :sound Fi l e];
115
Kapitel 4
12 13 14 15 16
Systemeigene Funktionen von QuickConnect
// ist die Audiodat ei zu lang zum Ab sp ielen //wird der Fehl er -1500 gemeldet OSStat us err or = AudioSer v icesCreat eSystemSound i DC
CCFURLRe f) url, &a Sound ) ;
17 Aud ioSer vicesPlaySystemSound( aSound ) ; 18 retu rn ni l : 19
Wie Sie in Zeile 4 des vorstehenden Beispiels sehen, wird die Variable aSound der Klasse
Sy stemSound iD auf den definierten Wert kSy stemSound iD_Vi bra t e gesetzt, wenn
der Parameter mit dem Index 1 den Wert -1 aufweist. Wenn nicht, wird ein Systemklang
aus der Datei l aser . wav erstellt, die in der Gruppe Re sou rces der Anwendung steht,
und die Variable aSound auf einen Bezeichner gesetzt, der für den neuen Systemklang
angelegt w ird.
in beiden Fä llen w ird die ( -Funktion Aud i oSe r v i ces Pl aySys temSound aufgerufen und
der Klang abgespielt bzw. das Gerät in Vibration versetzt. Handelt es sich um einen iPod
touch, werden Vibrationsanforderungen vom Gerät ignoriert. in einer echten Anwendung
mit mehreren Klängen lässt sich diese Funktion leicht erweitern, indem andere Zahlen als
Bezeichnerfür den abzuspielenden Klang übergeben werden.
Da die Variable vom Typ SystemSound I D tatsäch lich numerisch ist, sollten die System
klänge beim Start der Anwendung erstellt und ihre Bezeichner dem JavaScript-Teil zur
späteren Verwendung übergeben werden. Damit wird die Rechen last f ür das Neuerstel
len der Klänge bei j eder Anforderung vermieden und die Qualität des Benutzererlebnisses
gesteigert, wei l das Abspielen nicht verzögert wi rd.
Nachdem Sie die Übergabe von Befehlen von JavaScript an Objective-C gesehen und er
fahren haben, w ie Sie die Vibration auslösen oder einen ku rzen Klang abspielen, ist es
leicht zu verstehen, wie Sie Objective-C einen Befehl übergeben und die Ergebnisse an
den JavaScript-Tei l der Anwendung zurückgeben lassen.
Da diese Arten der Kommunikation ähnlich ablaufen, wird als Beispiel die GPS-Orts
ermittlung gezeigt, eine beliebte Funkt ion von iPhone-Anwendungen. Sie nutzt die Fäh ig
keit des QuickConnectiPhone-Frameworks zur bid irektionalen Kommunikation zwischen
JavaScript und Objective-C.
Wie bei allen vom JavaScript-Framework gesendeten Befehlen ist eine Zuordnung des
Befehls l oc erforderlich, damit die Daten abgerufen werden können und eine Antwort
zurückgehen kann.
116
Geräteaktivierung in Objective-c
[aControll er mapCommandToBCO:@" l oc" withFunction:@"LocationBCO"J:
[aControll er mapCommandToVCO:@"sendloc" withFunction:@" Locat i onVCO"J:
Hier gibt es zwei Zuordnungen, eine an ein Geschäfts- und eine an ein Ansichtssteuer
objekt. Wie in Kapitel 2 erörtert, sind Geschäftssteuerobjekte für die Abfrage, Ansichts
steuerobjekte dagegen für die Darstellung von Daten zuständig.
Da Geschäftssteuerobjekte fü r einen konkreten Befehl vom QuickConnectiPhone-Frame
work vor sämtlichen Ansichtssteuerobjekten ausgeführt werden, wird zuerst eine do
Command-Meldung an die Klasse Locat i onBCO gesendet, die die GPS-Daten abfragt und
zurückgibt. Die folgende Methode doCommand gehört zur Klasse Loc at i onBCO; sie führt die Aufrufe durch, die erforderlich sind, um das Gerät zum Suchen seiner GPS-Daten zu
veran lassen.
+ Ci d) doCommand : CNSArray*) parameters { Quic kConnect ViewCont ro l l er *contro l l er
(Quic kConnect Vi ewContro l l er*)[ parameters object Atlndex:OJ: [[cont rol l er l ocationManager ] startUpdatinglocati on ] ;
return ni l ;
Die Methode startet die GPS-Hardware durch Abfragen des ersten Elements im Parameter
array, das ihr übergeben wurde und sie anweist, die Hardware zu starten. Das Framework
setzt den ersten Parameter immer aufden Qui ckConnec t Vi ewControll er, damit dieser
bei Bedarf von den Geschäfts- oder Ansichtssteuerobjekten benutzt werden kann, die mit
einem Befehl verknüpft sind.ln allen Geschäfts- und Ansichtssteuerobjekten in Objective-C
beginnen sämtliche von JavaScript-Code gesendeten Parameter mit dem Index 1.
Das Qui ckConnectVi ewControl l er-Objekt besitzt ein integriertes Attribut der Klasse
CLLocat i onManager mit dem Namen l oca t i onManager, das von Ihrer Anwendung
nach Bedarf ein- und ausgeschaltet wi rd. Es ist w icht ig, diesen Manager nicht länger als
nötig laufen zu lassen, wei l er viel Batteriestrom verbraucht. Deshalb schaltet der vorste
hende Code die Ortshardware ein, indem er ihm jedes Mal, wenn ein Ort benötigt wi rd,
eine st a r t Updat i ng Loca t i on -Meldung sendet. Sobald der Ort gefunden ist, wi rd die
GPS-Hardware ausgescha ltet.
Obj ekte der Klasse CL Locat i onManage r verhalten sich asynchron, d.h., bei der Abfrage von Ortsdaten w ird eine vordefinierte Rückruffunktion aufgerufen, soba ld der Ort erm it
telt ist. Mithilfe dieser Funktion können Sie auf den Ortsmanager und zwei Orte zugreifen:
einen zuvor festgelegten und den aktuellen.
117
Kapitel 4 Systemeigene Funktionen von QuickConnect
Der Ortsmanager verfeinert die Ortsangaben für das Gerät schrittweise, wobei er die
Funktion d i dUpdateTo Locat i on mehrmals aufruft. Das folgende Codebeispiel soll
herausfinden, wie lange es dauert, den neuen Ort zu bestimmen. Zeile 9 stellt fest, ob es
weniger als fünf Sekunden sind, und beendet die Suche, wenn es so ist.
1 (vo i d) locationMana ger : (C LLocationManager *)manager 2 didUpdateTo l ocation: ( CLLocation *)newlocation 3 from l ocation:(CLLocation *)oldlocation 4 5 II wenn rel ativ kurz vorher erfolgt, Aktuali sierungen zwecks 6 II Stromersparnis ausschalten 7 NSDate* eventDa t e = newlocation.timestamp; 8 NSTimelnterval howRecen t =
9 [ eventDate timelnterva l SinceNow]; 10 if (abs ( howRecent ) < 5.0){ 11 [manager stopUpdating l ocation ]; 12 NSMutabl eArray *paramsToPass =
13 [[NSMutabl eArray all oc] in i tWithCapacity :2]; 14 [paramsToPass addObject:se l f]; 15 [paramsToPass addObject:newlocation]; 16 [[QuickConnect getlnstance] 17 handl eRequest:@" sendloc " 18 withParameters:paramsToPass];
19 20 II sonst Ereignis überspringen und nächstes verarbeiten. 21
Nach Beendigung der Ortssuche sendet der Code eine Meldung an den QuickConnectiPho
ne-Frontcontrol ler, die besagt, er solle eine send l Oe-Anforderung mit Qui ckConnect
Vi ewContro l l er, se l funddem neuen Ort als zusätzlichem Parameter behandeln.
Der Befehl send l oc ist dem Handler Locati onVCO zugewiesen, dessen Methode do
Command im folgenden Beispiel vorkommt. Sie fragt die UIWebView mit dem Namen
webVi ew aus dem Qui ckConnectVi ewContro l l er ab, von dem die ursprüngliche
Anforderung von GPS-Ortsdaten ausging. Anschließend legt sie die GPS-Daten im Array
pass i ngArray vom Typ NSArray ab.
Um die GPS-Daten an das webVi ew-Objekt zurückzusenden, muss das Array, in dem sie
stehen, in einen JSON-String konvertiert werden. Um aus dem Array vom Typ NSArray
einen String vom Typ NSStri ng zu machen, wird dieselbe Klasse SBJSON eingesetzt, mit
der zuvor aus einem JSON-String ein Array erstellt w urde. Es geschieht in Zeile 21 und 22:
118
Geräteaktivierung in Objective-c
1 + (id) doCommand: (NSArray*) pa ramet erst 2 QuickConnect ViewControll er *cont roll er 3 (QuickConnect ViewControll er*) [parame t ers 4 objectAt i ndex :O] ; 5 UIWe bVi ew *webVi ew = [cont rol l er webVi ew] ; 6 CLLocation *l ocat ion = (C LLocat ion*) [paramet er s 7 object At i ndex :1] ;
9 NSMu t ableArray *pass i ngArray = [ [ NSMutabl eArray all oc] 10 initWithCapac ity :3]; 11 [pass i ngAr ray addObject: [NSNumber numberWi thDoubl e : 12 l ocat i on .coord i nate . l atitude]] ; 13 [pass i ngAr ray addObject: [NSNumber numberWi thDoubl e : 14 l ocation.coordi nate .l ongitude ]] ; 15 [pa ss i ngAr ray addObject : [NSNumber numberWi th Fl oa t : 16 l ocat ion. al t itude ]]; 17 18 SBJSON *generator = [SBJSON al l oc] ; 19 20 NS Erro r *error ; 21 NSStr i ng *pa ramsToPass = [generato r 22 s t r i ngWithObject :passingArray error :&error ] ; 23 [generator rel ease] ; 24 NSStr i ng *jsStri ng = [[NSStr i ng all oc] 25 i ni tW i th Fo rmat :@" handl eJSONReques t ( I showl oc I I I %@ 1
) " .
26 paramsToPass] ; 27 [webVi ew 28 str ingByEva l uati ngJavaSc r i ptF romStr ing :jsStr i ng] ;
29 [pass i ngAr ray re l ease ] ; 30 re tu rn ni l ; 31
Nach dem Umwandeln der GPS-Ortsdaten in einen JSON-St ring, der für ein Array mit Zahlen steht, wird das JavaScript-Modul innerhalb des webVi ew-Objekts aufgerufen. Dazu wird zunächst ein St ring vom Typ NSSt ring angelegt, der den auszufüh renden JavaScript-Code enthält. in diesem Beispiel handelt es sich um ein handl eJSONReq uestObjekt, dem der Befehl showl oc und die GPS-Daten im JSON-Format als String übergeben werden. Wie in Abschnitt 1 gezeigt, führt diese Anforderung dazu, dass die GPS-Daten in einem d i v-Eiement in der angezeigten HTML-Seite erscheinen.
119
Kapitel 4 Systemeigene Funktionen von QuickConnect
Im Ansch luss an dieses Beispiel können Sie sich das Date Pi ckerVCO- und das Pi ck
Res u l ts V CO-Objekt im Beispiel Dev i ceCa ta l og ansehen und feststellen, dass derselbe
Ansatz verwendet wird, um die Standardselektoren für Datum und Uhrzeit auszugeben,
die sogenannten Picker, die Objective-C bereitstellt. Mit JavaScript innerhalb von UIWeb
View stehen Ihnen zwar auch vordefin ierte Picker zur Verfügung, die aber aus Benutzer
sicht nicht so gelungen sind wie die standardmäßigen von Objeetive-C. Mit diesen Stan
dardpickern und denen, die Sie möglicherweise definieren, ergibt sich für Ihre Web-Apps
ein angenehmeres Benutzererlebnis.
4.3 DIE ÜBJECTIVE- (-IMPLEMENTIERUNG DER
QUIC K(ONNECTIPHONE-ÄRCHITEKTUR
Der in Abschnitt 1 und 2 gezeigte Code stützt sich weitgehend auf eine Obj ective-C-Imple
mentierung derselben Arch itektu r, die in Kapitel 2 erläutert wurde. in diesem Abschnitt
geht es darum, wie die Umsetzung der Architektur in Objeetive-C erfolgt. Eine vollstän
dige Erläuterung der einzelnen Komponenten finden Sie in Kapitel 2, das die JavaScript
lmplementierung enthält.
Wie in der JavaScript-lmplementierung werden alle Verha ltensanforderungen über einen
Frontcontroller erledigt, der in Form der Klasse Qu i ckConnect implementiert ist, deren
Quel le die Dateien Qu i ckConnect. m und Qu i ckConnect . h sind. Da von vielen unter
schiedlichen Stellen innerhalb einer Anwendung Meldungen an diese Klasse gesendet
werden müssen, handelt es sich um ein Singleton (Entwurfsmuster).
Singleton-Klassen sind so geschrieben, dass dieser Klasse innerhalb einer Anwendung nur
ein einziges instanzi iertes Objekt zugewiesen werden kann. Bei korrektem Vorgehen gibt
es immer eine Möglichkeit, von einer beliebigen Stelle innerhalb der Anwendung einen
Zeiger auf dieses Einzelobjekt zu erhalten. Für das Singleton-Objekt von Qu i c kConnect w ird dazu eine Klassenmethode get I nstance erstellt, die eine Instanz von Qui ckCon
nect zurückgibt, die beim ersten Aufruf der Methode zugewiesen w ird.
Da es sich um eine Klassenmethode handelt, kann der Klasse eine get Ins ta n ce-Mel
dung gesendet werden, ohne ein Qu i ckConnect-Obj ekt zu instanziieren. Die Methode
gibt einen Zeiger auf die zugrunde liegende Qu i ckConnect-lnstanz zurück. Wie Sie im
folgenden Code sehen, weist sie dazu einem statisch defin ierten Qu i ckconnect-Zeiger
eine Instanz der Klasse zu.
+ (QuickConnect* )getinstan ce{
120
//da di ese Ze i l e stat i sch dekl ariert ist, //wi rd si e nur ei nmal ausge f ührt. stat i c Quic kConnect *mySelfQC = ni l ;
Die Objective-C-Implementierung der QuickConnectiPhone-Architektur
@synchr oni zed([Qui ckConnect cla ss ] ) { if (mySel fQC == nil ) {
mySelfQC = [ Qu i ckConnect singl eton ] ; [ mySelfQC i nit ]:
r et ur n mySelfQC ;
Die vor der lnitial isierung gesendete Einzelmeldung nutzt das Verha lten, das in der den
Qu i ckConnec t -Objekt en übergeordneten Klasse FTSWAbs t ractSi ng l eton defin iert
ist . Diese Oberklasse weist das eingebettet e Singleton-Verhalten zu, beispielsweise
over r i di ng new, c l one und andere Methoden, die j emand inkorrekt zur Zuweisung einer weiteren Qui ckConnect -lnstanz benutzen könnte. Deshalb lässt sich ein Oui ck
Connect -Obj ekt nur mithilfe der Methode get In sta n ce erstellen und verwenden. Nach
der Zuweisung muss ein Qui ckconnect -Obj ekt wie alle korrekt gebildeten Object ive-C
Obj ekte initialisiert werden.
Sowohl die Zuweisung als auch die lnitial isierung des Obj ekt s fi nden nur statt, wenn dem
Attribut mySe l fQC noch kein Qui ckConnect -Obj ekt zugewiesen wurde. Wegen des
Synchron isationsaufrufs, der die Prüfung auf ein instanziiertes Qui ckConnect -Obj ekt
umschließt, sind die Prüfung und die lnitial isierung th readsicher.
Eine weitere Methode der Klasse Qui ckConnect ist pa rameters. Wie die JavaScript Funktion ha ndl eRequest ( aCmd, pa ramete r s) in Kapitel2 stellt sie das Verfahren zur
Anforderung der Ausführung von Funkt ionalität in Ihrer Anwendung dar.
Der Methode werden ein Befehlsstring und ein Array mit Parametern übergeben. Im fol
genden Beispiel wi rd in Zeile 3 bis 9 eine Reihe von Meldungen an den Anwendungscont
roller gesendet . Zei le 3 und 4 f ühren zuvor Ansichtssteuerobjekte aus, die mit dem Befehl
verknüpft sind. Bestehen der Befeh l und die Parameter die Validierung, werden ggf mit
hilfe einer d i spa t ch ToBCO-Meldung die mit dem Befeh l verknüpften Geschäftssteuer
objekte ausgef ührt . Diese Meldung gibt ein Array vom Typ NSMutab l eAr ray zurück, das
die ursprünglichen Arraydaten von pa r amet e rs und zusätzlich alle Daten enthält, die von
einem aufgerufenen Geschäftssteuerobjekt gesammelt w urden.
1 - (vo i d) handl eRequest: (NSSt r i ng*) aCmd 2 with Parameters : (NSArray*) parameter s t 3 if( [ self - >t heAppCont ro l l er dispatchToVal CO : aCmd 4 wi thPa rame t ers :paramet er s ] != ni l ) { 5 NSMutabl eArray *newPa rame t ers =
6 [se l f - >theAppControll er di spat chToBCO : aCmd
121
Kapitel 4 Systemeigene Funktionen von QuickConnect
7 withParameters:parameters]; 8 [self - >theAppContro l l er dispatchToVCO:aCmd 9 withParameters:newParameters]; 10 11
Nach Abschluss des Aufrufs von d i spatchToBCO:withParameters wi rd eine
di spatchToVCO :wi thParameters-Meldung gesendet, was dazu führt, dass alle eben
fal ls mit dem betreffenden Befeh l verknüpften Ansichtssteuerobjekte ausgeführt werden.
Indem für alle Anforderungen von Funktionalität die Methode handl eRequest: wi th
Pa rameters verwendet wird, durchläuftjede Anforderung ein dreistufiges Verfahren:
1. Valid ierung
2. Ausführung von Geschäftsregeln {BCO)
3. Ausführung von Ansichtsänderungen {VCO)
Wie in der JavaScript-lmplementierung stellt jede d i s patchTo-Methode eine Fassade dar.ln
diesem Fa ll heißt die zugrunde liegende Objective-C-Methode d i spa tchToCO: wi th Para
meters.
Sie ruft zuerst al le mit dem Befehl defaul t verknüpften Befehlsobjekte und die in aMap
übergebenen Parameter ab. aMap enthä lt abhängig davon, welche Fassadenmethode
aufgerufen wurde, Geschäfts-, Ansichts- oder Validierungssteuerobjekte. Diese Standard
befeh lsobjekte werden, wenn vorhanden, abgerufen und fü r alle Befehle benutzt. Wollen
Sie, dass bestimmte Befehlsobjekte fü r alle Befehle verwendet werden, brauchen Sie sie
nicht j edem einzelnen Befehl zuzuordnen, sondern nur einmal dem Befehl defau l t.
Damit die abgerufenen Befehlsobj ekte verwendet werden, benötigen sie eine Meldung,
näml ich doCommand. ln Zeile 19 bis 23 des folgenden Codes wird diese Meldung als Selek
tor abgerufen und die Meldung performSel ector übergeben, was dazu führt , dass die
Meldung doCommand ausgeführt w ird, die Sie in Ihrem OCCommandübj ect-Obj ekt imple
mentiert haben.
1 - Cid) dispatchToCO: CNSString*)command withParameters: 2 CNSArray*)parameters andMap:CNSDictionary*)aMap{ 3 //ein mutabl es Array an l egen , dass sämt l iche 4 //vorhandenen Parameter enthäl t. 5 NSMutabl eArray *resul tArray; 6 if(parameters = nil ){ 7 resultArray = [ [ NSMutabl eArray al l oc ] 8 initWithCapacity:O ];
122
Die Objective-C-Implementierung der QuickConnectiPhone-Architektur
9 10 else{ 11 12 13
resultArray [[NSMutableArray al l oc] initWithArray:parametersJ:
14 //das Ergebnis auf etwas setzen, damit 15 //d ie Ausführung fortgesetzt wird, 16 //wenn keine Zuordnungen stattfinden . 17 id result = @"Continue" : 18 if( [aMap objectForKey:@"default"J != ni l ){ 19 SEL aSelector = @sel ector(doCommand); 20 whi l e((resul t = [ ((QCCommandObject*) 21 [aMap objectForKey:@"defau l t "J) 22 performSel ector:aSel ector 23 withObject: parameters]) != nil){ 24 if (aMap == se l f ->businessMap){ 25 [resul tArray addObject:resul t ] ; 26
27 28 29 //wenn al l e Methodenaufrufe der Standardbefehl sobjekte 30 //etwas zu rückgeben, al l e benutzerdefinierten ausführen . 31 if(resul t != ni l && [aMap objectForKey:command ] != 32 nil ){ 33 NSArray *t heCommandObjects = 34 [a Ma p objectForKey :commandJ : 35 int numCommandObjec ts = [theCommandObjects count ] ; 36 for(int i = 0: i < numCommandObjects ; i ++){ 37 QCCommandObject *theCommand =
38 [ t heCommandObjects objectAt i ndex:iJ: 39 resu l t = [theCommand doCommand:parameters]; 40 if( result == nil ){ 41 resu l tArray = ni l : 4 2 brea k: 43 44 4 5
4 6
47 48
if (aMap == se l f ->businessMap){ [ resu l tArray addObject:resul t];
123
Kapitel 4 Systemeigene Funktionen von QuickConnect
49 NSMutabl eAr ray* r esultAr r ayCopy =
[ NSMutabl eArr ay arrayWi thArray :resul t Ar ray ] ; 50 [ r esul tArray release] ;
51 i f ( aMap == sel f- >businessMap ) { 52 ret urn r esul tArrayCopy ; 53 54 return r esul t; 55
Nachdem alle doCommand-Meldungen an alle Objekte von QCC ommandObj ec t gesendet
wurden, die Sie dem Objekt de f au l t zugeordnet haben, geschieht dasselbe für Obj ekte
von QCComma ndObj ect, die Sie dem der Methode als Parameter übergebenen Befehl zu
geordnet haben. Die QCCommandOb ject -Obj ekte haben dieselbe Existenzberechtigung
w ie die Steuerfunktionen in der JavaScript-lmplementierung. Da Objekte von OCComma nd
Obj ect den gesamten Verha ltenscode für Ihre Anwendung enthalten, wird mithilfe eines
Beispiels leichter verständlich, w ie sie angelegt werden.
QCComma ndOb ject ist die übergeordnete Klasse von Loggi ngVCO. Daher muss
Loggi ngVCO die Methode doCommand umsetzen. Es folgt der gesamte Inhalt der Datei
Loggi ngVCO. m in der Beispielanwendung Devi ceCat a l og. Ihre Methode doComma nd
schreibt in die Protokolldatei der laufenden Anwendung. Dieses Ansichtssteuerobjekt
protokolliert Fehlersuchmeldungen aus dem JavaScript-Code Ihrer Anwendung. Abbi l
dung 4.2 zeigt die dafür notwendigen Aufrufe.
Die Methode doCommand der Klasse Logg i ngVCO ist kurz. Das sollte für doCommand
Methoden für die verschiedenen Befehlsobjekte grundsätzlich so sein. Sie sollten nur eine
Aufgabe erledigen, und das gut. Wenn Sie feststel len, dass eine solche Methode, mit der Sie
arbeiten, lang wird, sollten Sie möglicherweise daran denken, sie in logische Komponenten
zu untertei len und mehrere Klassen fü r Befeh lsobjekte anzu legen. Wenn diese Methoden
zu lang werden, befassen sie sich nämlich wahrscheinlich mit mehr als einer Aufgabe.
Im folgenden Beispiel besteht die »eine Aufgabe«, die das Loggi ngVCO-Objekt erledigt,
im Protokollieren von Meldungen in der Feh lersuchkonsole von Xcode. Diese wen ig um
fangreiche Komponente lässt sich natürlich in vielen Befehlen in Verbindung mit anderen
Befehlsobjekten wiederverwenden.
124
Die Objective-C-Implementierung der QuickConnectiPhone-Architektur
1 aute~cconn•C!rtwcontr•"" 1 1 oulc~, •• ",!C, 1 1 Aopn .....
1eo .... " ... 1
: .-:-. '
Ohf:VldeReQUes11'100iteSSO!Oie' , flfSSO:Qf) •
' ' ' ' ' ' ' ' ' U dtspatchToSCO(toc'. messaoe> ~spaX;hToCO (bgMes..o;.aoe·. message, 'liewMap)
::, --~~~~~~~ doColmlar<l(message)
' ' '
- ---== ==""'---- 0 ' : ' ' ' '
~ Abbildung 4.2: Ein Sequenzdiagramm zeigt die in Objective-C aufgerufenen Methoden für die Behandlung einer Anforderung zum Protokollieren einer JavaScript-Fehlersuchmeldung.
Das Verhalten dieses Ansichtssteuerobjekts besteht aus einer einzigen Zei le, die die Funk
tion NS Log ausführt. Dabei w ird das erste Obj ekt im Parameterarray an einen statischen
String angehängt und ausgegeben.
#import "LoggingVCO.h "
@impl ementation LoggingVCO
+ Cid) doCommand:CNSArray*) parameters{ NS Log(@"JavaScriptMessage: %@" ,
[parameters objectAt i ndex:l]); return ni l ;
@end
125
Kapitel 4 Systemeigene Funktionen von QuickConnect
Damit diese Protokol lierung stattfindet, muss eine Zuordnung zwischen dem Befehl l og
Message und der Klasse Loggi ngVCO erst ellt werden. Wie in der JavaScript-lmplementie
rung werden dazu l ogMessageals Schlüssel und der Name der Klasse l oggi ngVCO als
Wert in eine Zuordnungstabelle geschrieben.
Die Zuordnung erfolgt in der Datei QCCommandMapp i ngs. m. Derfolgende Code stammt
aus dieser Datei in der Beispielanwendung Dev i ceCata log und ordnet l ogMessageder Klasse Loggi ngVCO zu.
[aCon t ro l l er mapCommandToVCO:@"logMessage " withFunct i on:@"LoggingVCO "J:
Dem Anwendungscontroller wird die Meldung mapCommandToVCO:wit hFunction
übergeben, in der der Befehl der erste und der Name des Ansichtssteuerobjekts der zweite
Parameter ist. Diese und andere ähnliche Methoden zum Zuordnen der übrigen Befehls
objekta rten sind Fassaden, die die jeweilszugrunde liegende ma pComma ndT oCO-Methode
aufrufen.
Diese mapCommandToCO-Methode ermöglicht die Zuordnung mehrerer Befeh lsobjekte zu
einem einzigen Befeh l, indem sie den Befeh l einem Array vom Typ NSMutab l eArray zu
ordnet. Anschließend wird dieses Array benutzt, um die Cl a s s-Obj ekte aufzunehmen, die
dem als zweitem Parameter übergebenen Klassennamen entsprechen. Derfolgende Code
implement iert die Methode mapCommandToCO.
- (vo i d) mapCommandToCO:CNSString*)aCommand wit hFunct ion:(NSString*)aCl assName t oMap:CNSMutab l eDictionary*)aMap {
NSMutabl eArray *contro l übjects =
126
[ [aMap object ForKey:aCommand ] re t ai nJ: if (control übjects == ni l ){
NSMutabl eArray * tmpCn t r l Objs = [[NSMutabl eArray al l oc] i nitWi thCapacity: l];
[ aMap setübject: tmpCntr l Objs forKey:aCommandJ: contro l übjects = tmpCntr l Objs; [tmpCntr l Objs re l ease];
//D i e Steuerobjekt kl asse für den gegebenen //Namen abfragen und ein Objekt des betreffenden //Typs i n das Array für den Befeh l einfügen. Cl ass aCl ass = NSCl ass FromString(aCl assName); if(aCl ass != ni l ){
[ contro l übjects addObject:aCl ass];
Zusammenfassung
else{ MESSAGE( "unable t o fi nd the %@ cl ass.
Make sure tha t it exists under this name and try again. " );
Das Einfügen der Klassenobjekte in ein Array vom Typ NSMutab l eArray bietet die Mög
lichkeit, eine beliebige Anzah l von Befehlsobjekten gleichen Typs, etwa Ansichts- oder
Geschäftssteuerobjekte oder andere, demselben Befehl zuzuordnen und dann einzeln in
der Reihenfolge auszuführen, in der die mapCommandTo-Meldungen gesendet wurden.
Auf diese Weise lassen sich mehrere Ansichtssteuerobjekte nacheinander ausführen.
Siekönnen beispielsweiseein Ansichtssteuerobjekt verwenden, daseine U IView anzeigt, auf
das ein weiteres folgt, das die Undurchsicht igkeit einer anderen UIView ändert, und darauf
die Protokollierung einer Meldung folgen lassen. Dafür reicht es, drei ma pCommandToVCO
Meldungen mit demselben Befehl, aber drei verschiedenen Namen von Befeh lsobjekten zu
senden.
ln der Beispielanwendung Devi ceCa ta l og gibt es noch mehr Beispiele fü r Geschäfts
und Ansichtssteuerobj ekte. Sie werden durch Anforderungen vom JavaScript -Teil der An
wendung aktiviert.
4.4 ZUSAMMENFASSUNG
ln diesem Kapitel haben Sie erfahren, w ie Sie einige wünschenswerte iPhone- und iPod
touch-Merkmale aus Ihrer JavaScript-Anwendung heraus aktivieren. Die Nutzung von
G PS-Ortsdaten, Besch Ieu n igu ngsmesswerten, der Vibrationsfunktion und der Audiofäh ig
keiten erweitern das Ausstattungsspekt rum Ihrer Anwendung.
Wenn Sie sich die in Dev i ceCata l og enthaltenen Beispiele ansehen und mit Objective-C
arbeiten, sol lten Sie in der Lage sein, weitere Merkmale wie das Durchsuchen des Bonjour
Netzwerks auf in der Nähe befindliche Geräte, das Hinzufügen, Löschen und Abfragen von
Kontaktdaten aus der Kontaktdatenanwendung oder das Hinzufügen, Löschen und Abfra
gen anderer integrierter Verhaltensweisen einzufügen, die in Objective-C-Anwendungen
zur Verfügung stehen.
Ihre JavaScript -Anwendung kann mithilfe des in diesem Kapitel beschriebenen Ansatzes
fast alles verwirklichen, was eine reine Objective-C-Anwendung beherrscht. Ein Beispiel
daf ür finden Sie in Kapitel 7, in dem Sie lernen, wie Sie Google-Karten in eine beliebige
Anwendung einbetten, ohne das Aussehen und die Anmutung der Kartenanwendungvon
Apple zu beseitigen.
127
Google Maps einbetten
Häufig brauchen Sie in einer iPhone-Anwendung eine Möglichkeit, um Landkarten anzu
zeigen. Dazu gibt es verschiedene Mögl ichkeiten. Sie können die Anwendung schließen
und die normale iPhone-Anwendung Karten starten, aber auch Google-Standardkarten
verwenden. Beide Ansätze weisen ihre Grenzen auf. in diesem Kapitel erfahren Sie, w ie Sie
eine Google-Landkarte erstellen und verwenden, die sich wie die iPhone-Standardanwen
dung Karten verhält, ohne dass Sie dazu Ihre Anwendung schließen müssen.
5.1 ABSCHNITT 1: EINE KARTE IN EINER JAVASCRIPT
ÄNWENDUNG MIT QUICK(ONNECT ANZEIGEN
Für Ingenieure und Programmierer gibt es verschiedene Möglichkeiten, um fürWeb-Apps
auf dem iPhone Landkarten zu verwenden. Am einfachsten ist es, in der Anzeige einen Link
hinzuzufügen, der mit http://maps.google.com beginnt und zu dem gewünschten Karten
material führt. Wenn der Benutzer auf diesen Link tippt, wi rd die Anwendung beendet
und die Standardanwendung Ka rten geöffnet, die dann die gewählte Landkarte anzeigt.
Dieser Ansatz lässt sich einfach verwenden und schnel l umsetzen. Der Nachtei l besteht
aber daran, dass Ihre Anwendung geschlossen w ird, was al lgemein als schlechtes Saft
waredesign gilt. Eine Anwendung mit einem solchen Verhalten wirkt wie Fl ickschusterei.
Benutzer bevorzugen eine besser in die Anwendung integrierte Lösung.
Kapitel 5 Google Maps einbetten
Es gibt noch einen weiteren Nachteil. Google kann mehrere Stecknadelsymbole zwar als
Reaktion auf eine Suchanfrage wie »Pizza« anzeigen, aber nicht für bestimmte von Ihnen
definierte Orte. Nehmen wir z.B. eine Anwendung, in der Sie Stecknadeln an verschiede
nen Orten in einer Stadt anzeigen lassen möchten, die aber nicht mit suchbaren Begriffen
w ie »Pizza« verknüpft sind.ln der URL-Anforderung, die Sie an Google senden, können Sie
zurzeit keine Positionen für mehrere Stecknadeln mit Beschreibung angeben. Diese Ein
schränkung kann ärgerlich sein, wenn Sie z.B. die Länge und Breite eines Ortes verwenden
möchten, um dort eine Stecknadel anzuzeigen.
Ein anderer Ansatz besteht darin, in Ihrer Anwendung das durchzuführen, was Sie auf einer normalen Webseite machen würden. Das heißt, Sie verwenden die AJAX-API von
Google, um eine Landkarte in einen d i V-Bereich der angezeigten HTML-Seite einzubetten.
Dann können Sie die JavaScript-API von Google nutzen, um die einzelnen Stecknadeln zu
setzen.
Dabei bleibt zwar der Benutzer in Ihrer Anwendung, aber auch dieser Ansatz weist Nach
tei le auf. Erstens ist es in der U I WebVi ew, in der Sie die Karte anzeigen, nicht möglich, inner
halb der di V-Bereiche zu blättern. Die Berührungs- und Verschiebungsereignisse werden
auf einer sehr viel tieferen Ebene verarbeitet und werden nicht an den von Google bereit
gestel lten Java Script-Code gesendet, der dieeingebettete Landkarte handhabt. Das bedeu
tet, dass Sie die Karte zwar anzeigen, aber den dargestellten Ort nicht ändern können.
Ein weiteres Problem bi ldet die Größe der Sprechblasen mit Informationen zu den Orten,
die in Google angezeigt werden. Sie sind f ür die Darstel lung im Browser eines ausgewach
senen Computers dimensioniert. Auf dem iPhone dagegen bedeckt eine solche Sprech
blase einen Großteil der Karte. Außerdem liegt die Sprechblase größtenteils außerha lb
des Bildschirms und kann daher aufgrundder erwähnten Einschränkung fü r das Blättern
nicht gelesen werden. Es ist zwar möglich, die Größe des Inhalts dieser Sprechblasen zu
ändern, nicht aber die Größe der standardmäßigen Google-Sprechblasen selbst.
Es wäre offensichtlich am besten, die Ka rte wie im zweiten Ansatz in die Anwendung ein
zubetten und dadurch mehrere Stecknadeln anzeigen zu können, aber gleichzeitig die
Möglichkeiten zum Blättern und zur Anzeige aus dem ersten Ansatz beizubehalten. Das
Framewerk QuickConnectiPhone enthält eine Komponente, die es Ihnen ermöglicht, mit
hilfe eines JavaScript-Auf rufs so vorzugehen.
Das Xcode-Projekt MapExamp l e zeigt, wie Sie dabei vorgehen müssen. Sie können dieses
Projekt als Tei l der Datei QuickConnctiPhone.zip von http:llsourceforge.netlprojectslquickconnect/ herunterladen. Dieses Beispielprojekt finden Sie im Verzeichnis iPhone Examples.
130
Eine Karte in einer JavaSaipt-Anwendung mit QuickConnect anzeigen
Der Hauptbi ldschirm dieses Beispiels besteht aus einer einzigen HTML-Schaltfläche, wie Sie in Abbildung 5.1 sehen. Der Listener oncl i ck dieser Schaltfläche ist auf die Funktion s howTheMa p gesetzt, die Sie in der Datei mainjs des Projekts finden und die im folgenden Code wiedergegeben ist. Sie richtet vier Orte ein, nämlich Rexburg in ldaho, Wyoming, einen Sandwich-Laden und eine Position in der Wi ldnis.
function showTheMap (event) {
II Ein Ort besteht aus Breitengrad , Längengrad und Beschreibung var locationsArray = new Array(); rexburg = new Array(); rexburg . pus h(43 .82211) ; rexburg.push( -111.76860); rexburg.pus h( "County Court Hause "); l ocationsArray . push(rexburg) ;
var wyoming = new Array() ; wyoming.pus h(42 .86); wyoming.pus h( -109 . 45) ; wyoming.pus h( "Wyoming Pl ace ") ; l ocationsArray . push (wyomi ng ) ;
var wi l derness = new Array() ; wi lderness . push( 45 .35 ) ; wi l derness . push( -115 ) ; wi l derness . push( "River of No Return Wi l derness"); l ocationsArray . push (wi l derness);
var SandwichShop = new Array() ; sandwichShop.pus h(42.86); sandwichShop.pus h( -112.45); sandwichShop.pus h( "Somewhere Sandwiches"); l ocationsArray . push (sandwichS hop) ;
showMap(event, locationsArray);
131
Kapitel 5 Google Maps einbetten
~ Abbildung 5.1: Hauptbildschirm der Anwendung Ma pExamp l e mit der HTML-Schaltjläche
Jeder Ort ist ein Array aus drei Elementen, dem Breitengrad, dem Längengrad und einer
ku rzen Beschreibung, die mit der Steckn adel angezeigt wird. Die einzelnen Orte werden
zu l ocat i onsArray hinzugefügt. Die Reihenfolge der Werte für die einzelnen Orte ist
festgelegt, die Reihenfolge der Orte in l ocat i onsAr r ay dagegen ist beliebig.
in der Praxis können die Werte für die einzelnen Orte in einer Datenbank gespeichert sein,
aus einem RSS-Feed oder einer anderen Quel le abgerufen werden. Sie können sie sogar
abrufen, während Ihre Anwendung läuft. Wenn Sie die Postanschrift kennen, kann die Geo
code-JavaScript-API von Google daraus den Breiten- und Längengrad bestimmen (siehe
http:l/code.google.com/intl!de-DE!apis/mapsldocumentation/services.htmi#Geocoding_
Object). Wenn Sie diesen Vorgang zur Laufzeit erledigen, ist er jedoch langsam. Besser ist
es, Längen- und Breitengrad der gewünschten Orte beim Entwurf mit einem Stapelverar
beitungsprozess zu ermitteln und vor der Auslieferung der Anwendung zu speichern.
Nachdem Sie das JavaScript-Array mit den erforderlichen Orten erstellt haben, w ird es an
die Funktion showMap des Frameworks übergeben. Ebenfal ls übergeben wi rd das Ereig
nis, das den Aufruf dieser Funktion ausgelöst hat. Jetzt übernimmt das Framework die
Steuerung und verwendet die in Kapitel 4, »GPS, Beschleunigungsmessung und andere
systemeigene Funktionen von QuickConnect«, beschriebene Funktion ma keCa l l und
132
Eine Karte in einer JavaSaipt-Anwendung mit QuickConnect anzeigen
weist ihren Objective-C-Teil an, eine Landkarte mit Stecknadelsymbolen an den einzelnen
Orten anzuzeigen, wie Sie in Abbildung 5.2 sehen.
,.. Abbildung 5.2: Die Anwendung MapEx amp 1 e zeigt eine Stecknadel für jeden Ort an.
Das Framewerk zeigt die Ka rte in einem Objekt der Obj ect ive-C-Kiasse Ma pV i ew an. Diese
in Abschnitt 2 beschriebene Klasse ermöglicht dem Benutzer, die Anzeige der Karten wie
in der Apple-Anwendung Karten durch Antippen und Sch ieben zu steuern. Der Benut zer
kann auch auf eine St ecknadel doppelt ippen, um die Karte auf diesen Ort zu zent rieren
und zu vergrößern.
Wenn der Benutzer einmal auf eine Stecknadel tippt, wi rd ähnlich w ie in der Anwendung
Karten in einem kleinen schwarzen Feld eine Beschreibung eingeblendet (siehe Abbildung
5.3). Zieht der Benutzer eine Stecknadel, so w ird sie zu der neuen Posit ion auf der Ka rte
verschoben.
Wenn der Benutzer die Karte nicht mehr braucht, t ippt er auf die Schaltfläche DONE (FER
TIG), worauf hin die MapVi ew verschwindet. Die Anwendung wird w ieder in dem Zust and
dargest ellt, in dem sie vor der Anzeige der Kart e wa r. Im Gegensatz zu dem Ansatz, die
Anwendung zu schließen, die Anwendung Kart en zu öffnen, diese Anwendung wiederum
zu schließen und dann die alte neu zu start en, best eht hier kein Problem der Usability und
der Wiederherstellung des alten Zustands.
133
Kapitel 5 Google Maps einbetten
.,.. Abbildung 5-3: Die Anwendung MapExamp l e zeigt eine kurze Beschreibung an.
Durch den Aufruf der JavaScript-Funktion showMa p des Framewerks gewinnt Ihre Anwen
dung eine integrierte Funktion zur Kartenanzeige.ln Abschnitt 2 erfahren Sie mehr darü
ber, wie Ma pV i ew und andere Objective-C-Kiassen gestaltet sind und verwendet werden.
5.2 ABSCHNITT 2: DIE ÜBJECTIVE-(-IMPLEMENTIERUNG DES
KARTENMODULS VON QUICK(ONNECT
Das Ka rtenmodul von QuickConnect besteht aus drei Klassen:
> MapVi ew - Das Hauptelement zur Anzeige von Landkartenbi ldern
> Pi n - Eine benutzerdefinierte Stecknadel, die an einem Ort angezeigt werden kann
> I nf oW i ndow - Eine Klasse zur Anzeige einer kurzen Beschreibung bei einer Steck-
nadel
Abbildung 5-4 zeigt die Beziehungen zwischen diesen Klassen. Jede Ma pV i ew kann über
mehrere Pi ns verfügen, und j eder Pi n muss mindestens eine Ma pV i ew haben. Außerdem
besteht eine 1:1 -Beziehung zwischen Pi ns und I nfoWi ndows, d.h., es muss für j eden Pi n
ein I nfoWi ndow und fü r jedes I nfoWi ndow einen Pi n geben.
MapView t-11-----*-11 Pin t-11-----1-tl lnfoView
.,.. Abbildung 5.4: Die Klassen im Kartenmodul und ihre Beziehungen
134
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
Da eine Objective-C-Anwendung von Natur aus modular ist, muss sie direkt mit der Klasse
MapVi ew und deren API interagieren. Diese API besteht nur aus einer einzigen Methode,
näml ich i nitWith Frame: andLocat i ons. Beim Aufruf dieser Methode wird eine Karte
generiert, Stecknadeln werden darauf platziert, und eine kurze Beschreibung wird für Be
nutzer bereitgestellt, die auf die Stecknadel tippen. Außerdem wird dafür gesorgt, dass die
Karte auf die Stecknadel oder den Ort zentriert und vergrößert wird, auf den der Benutzer
doppeltippt. Derfolgende Code zeigt, wie die MapView-API im Framework QuickConnect
verwendet wird.
Wie bei GPS-Ortung, Debugging und den anderen in Kapitel 2, »Die Modularität von
JavaScript für iPhone-Anwendungen«, beschriebenen Anforderungen verwendet der Auf
ruf zur Anzeige einer Landkarte den Frontcontroller sowie Anwendungscontroller. Auch hier ist der Befehl showMap über die Datei QCCommandMappings.m mit dem VCO show
MapVCO verknüpft. Die Methode doCommand dieses VCO ist klein und besteht hauptsäch
lich darin, die in der JavaScript-Anforderung übermittelten Längen- und Breitengrade
sowie die ku rze Beschreibung in ein Array zu packen. Dazu wird das erste Element des
Parameterarrays übersprungen, da es sich dabei um den Qui ckConnetVi ewContro l l er
für die Anwendung handelt. Die im folgenden Code gezeigte Methode doComma nd finden
Sie im Xcode-Proj ekt Map Examp l e, das Sie von http:l/sourceforge.netlprojectslquickconnect herunterladen können.
+ Cid) doCommand:CNSArray* ) parameters { NSRange aRange = NSMa keRange(l, [parameters count ] - 1); NSArray * l ocations = [ parameters subarrayWithRange:aRange ] ; I I Dimensioniert die MapView bi l dschirmfül l end MapView *aMapView = [[MapView all oc ] initWithFrame:[[ UIScreen
mainScreen] app l icationFrame] andLocations: l ocations]; QuickConnectViewControll er *theControll er =
[ parameters objectAt l ndex:O ] ; II Fügt die MapView zur Hauptansicht der Anwendung hinzu [ [ [ theContro l l er webView]
superview] addSubview:aMapView]; return ni l ;
Da der Qui ckConnectVi ewContro l l er einen Verweis auf die U I WebVi ew enthält, die
die Anzeige anzeigt und ausführt, kann er verwendet werden, um einen Zeiger auf die
Hauptansicht der Anwendung zu gewinnen. Dazu w ird die Nachricht supervi ew an die
U IWebVi ew gesendet. Die neue MapVi ew wird dann der Hauptansicht der Anwendung
135
Kapitel 5 Google Maps einbetten
hinzugefügt, indem sie in der Nachricht addSubv i ew als Parameter übergeben w ird.
Nachdem diese Nachricht gesendet wurde, erscheint die MapVi ew und füllt den Bi ld
schirm aus, sodass die UI WebV i ew verdeckt wird.
Da der Funktionsumfang von MapVi ew ein abgesch lossenes Modul bildet, kann er leicht
in vielen verschiedenen Anwendungen wiederverwendet werden (in Kapitel 2 erfahren
Sie mehr über Modularität). Er lässt sich sogar mit wenigen internen Änderungen zur
Anzeige von Karten in hybriden Macintosh-Anwendungen einsetzen.
Alle Google-Karten sind unabhängigvon ihrem lnhaltWebseiten. Daher hat das MapV i ew
Objekt als Attribut eine eigene UIWebVi ew namens webMapVi ew. Dabei handelt es sich
nicht um die Instanz von U IWebVi ew, die die Anwendung anzeigt.
Wie Sie im folgenden Code sehen, zeigt webMapVi ew die Datei mapView.html an, die Sie
in der Gruppe RESOU RCES MAPVIEW finden. Als ihrDelegate ist die Klasse MapVi ew fest
gelegt. Die Ma pV i ew-Gruppe enthält sowohl eine eingebettete U I Vi ew als auch einen
WebVi ewDe l ega t e, der sich um alle Ereignisse fü r die U I WebVi ew kümmert.
1 - Cid) i nitWithFrame:CCGRec t )frame 2 and l ocations:CNSArray*) al ocat ion l ist 3 if (se l f = [ super i nitWi t hFrame: frame]) { 4 OKToTouch = NO ; 5 se l f . l ocations = [a l ocationl i st objectAt i ndex:1]: 6 frame.or igin .y -= 20: 7 UIWebView * aWebView = [ [ UIWebView al l oc]
8 i nitWithFrame: frame] : 9 se l f .webMapView = aWebView:
10 [ aWebView re l ease ]; 11 12 aWebView. user i nt erac t ion Enabl ed = NO ; 13 // Leg t al s Del egate f ür die WebV iew 14 // die WebView se l bs t fes t 15 [ aWebView setDel egate:sel f ]; 16 17 // Best immt den Pfad zur Date i mapView . html 18 //im Verzeichni s Resources 19 NSStr i ng *fi l ePathString = [[ NSBundl e mainßundl e]
pathForResource:@"mapView "of Type:@"ht ml " J : 20 MESSAGE(@"%@", fi l ePathStr ing) ; 21 // Ers t el l t den URL und die Anforderung der 22 II Datei mapVi ew. html 23 NSURL *aURL = [NSURL fi l eURLWithPath:fi l ePa t hString];
24 NSURLReques t * aRequest =
136
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
25 26
[NSURLRequest requestWithURL:aURLJ :
27 II Lädt die Datei ma pV iew .html in die WebView 28 [aWebView l oadRequest:aRequest]: 29 30 II Fügt die WebView zur I nhaltsans i cht hinzu 31 [se l f addSubview:self.webMapViewJ: 32 33 return self: 34
Man könnte meinen, dass zur Vereinfachung auch auf die Klasse Ma pVi ew verzichtet
werden könnte. Dies ist jedoch nicht der Fall. Da die U I Web Vi ew alle Berührungsereignis
se verarbeitet und nicht dafür sorgt, dass solche Ereignisse von den von ihr angezeigten HTML-Eiementen verarbeitet werden, würde sonst das in Abschnitt 1 beschriebene Prob
lem auftreten, das der Benutzer in der Karte nicht verschieben kann.
Um dieses Problem zu lösen, schaltet Zei le 12 des vorstehenden Codes die Verarbeitung
der Ereignisse durch die entha ltene UI WebVi ew ab. Dadurch kann das umschließende
MapV i ew-Obj ekt alldiese Ereignisse als Delegate verarbeiten. Der Delegate muss dann
die U IWebVi ew anweisen, in der Seite, die in ihr enthalten ist, zu verschieben.
Um eine Karte zu verschieben, müssen Sie erkennen können, ob eine Berührung in einer
Verschiebebewegung fortgeführt wurde. Dazu implementieren Sie die Standardmethode
touchesMoved: wi thEvent von MapVi ew.
- (voi d)touchesMoved :(NSSet *)touches wit hEvent:(U I Event *)event{
if(OKToTouch ){ i f ([ touches count ] == 1 ){
UITouch *touch = [touches anyObject ]; CGPoint prevloc =
[ t ouch previous l oca t ion i nView:sel f ]; CGPoint curloc =
[ t ouch l ocationinView:sel f ]; double touchDe l taX cur l oc . x - prevloc . x; double touchDe l taY = cur l oc .y - prevloc .y ;
NSString *javaScriptCall = [ [NSString al l oc ]
ini tWithFormat:@"s crol l (%f , %f ) " ,touchDe l taX, touchDel ta YJ :
NSString *resul t = [ webMapView
137
Kapitel 5 Google Maps einbetten
stringßy Eva1uatingJavaScriptFromString: javaScri pt Ca 11 ] ;
i f( [ res u1 t compare:@"true" J 0){ int numP ins = [ pi ns count ]: for(i nt i = 0: i < numPins: i++)(
Pin *aPi n =
[pins objectAtlndex:i J : [aP i n moveX:touchDe l taX
andY:touchDel taYJ: [aPin.info moveX:touchDel taX
andY:touchDe l taYJ:
el se if( [touches count] 2){ II Kneifbewegung
Diese Implementierung von touchesMoved :wi t hEvent bestimmt zunächst, wie weit
die Berührung fortgefüh rt w urde. Dazu w ird der Abstand (der Deltawert) zwischen der
Position des aktuellen und des vorhergehenden Ereignisses bestimmt und an die HTML
Seite in webMapVi ew übergeben. Dazu w ird mit dem Aufruf der JavaScript-Funktion
scro 11 die Nachricht st ri ngßy Eva 1 uat i ngJavaScri ptFromStri ng gesendet.
Die JavaScript-Funktion sc ro 11, die Sie im folgenden Code sehen und in der Datei map.
js der Gruppe RESOURCES MAPVIEW finden, verwendet die JavaScript-API f ür Google-Land
ka rten, um eine anzeigbare Karte neu zu zentrieren. Dazu w ird die angeforderte Änderung
zu den x-u nd y -Werten des aktuellen Kartenmittelpu nkts addiert und dann das Ka rten
objekt angewiesen, sich auf diese neue Position zu zentrieren.
funct ion scro11 (de1ta X, del taY){
138
try{ var centerPoint = ma p.fromlat l ngToDi vPixel (map.getCenter ()) ; centerPoint.x -= del taX: centerPoint. y -= del taY: var center l at l ng =
map.fromDi vPixel Tola t l ng ( centerPoint) ; ma p. setCenter(center l at lng);
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
catch(error){ return fa l se;
return true;
Wird diese JavaScript-Funktion erfolgreich abgesch lossen, so gibt sie true zurück, sodass
der Rest der Methode touc hesMoved: wi thEvent al le angezeigten Stecknadeln anwei
sen kann, ebenfa lls den Standort zu wechseln.
Da die Verarbeitung durch die zugrunde liegende U IWebV i ew ausgeschaltet ist, damit der
Benutzer die Karte verschieben kann, können die Stecknadeln normaler Google-Karten nicht
feststellen, dass sie berührt wurden. Daher können die standardmäßigen Sprechblasen für
die Beschreiung dieser Stecknadeln nicht angezeigt werden, weshalb es notwendig w ird,
eine eigene Pi n-Kiasse zu erstellen.
Diese Klasse, die Sie in der Gruppe (LASSES: MAPVIEW fi nden, verwendet das Bild pinlnserted.png aus der Gruppe RESOURCES: IMAGES zur optischen Darstel lung. Diese Datei können
Sie aber j ederzeit durch eine andere Bilddatei Ihrer Wahl ersetzen.
Fü r jeden Ort, den Ihre Anwendung von der JavaScript-Seite aus sendet, w ird ein Obj ekt der
Klasse Pi n init ialisiert. Dazu wird die im folgenden Code gezeigte Methode i nitWith
Frame : a nd I mage: a nd Loca t i on : aufgerufen. Diese Methode erstellt eine U I ImageVi ew
fü r das Bi ld der Stecknadel, legt deren Posit ion fest und scha ltet die Verarbeitung der Ereig
nisse ein, indem sie das Attributuser I nte ract i on Enab l ed desObj ektsauft rue setzt.
- ( id )i nitWithFrame: ( CGRect )frame and i mage:(NSString*)an i mage and l ocation: (MapViewl oca t ion)a l ocation{
if ( self = [super initWith Frame :frame]) UI ImageView * pinimage = [ [U I I mageView al l oc] ini tWithi mage: [ UI I mage imageNamed :an i mage] J : [self addSubview: pin i mage]; [ pin i mage re l ease]; l ocation = aloca t ion : self.user i nteractionEna bl ed = YES: self. backgroundCol or = [ UICol or cl earColo r ] :
return se l f:
Durch die Aktivierung der Benutzerinteraktion w ird das Pi n-Obj ekt fü r die pi nto-Ereig
nisse verfügbar und kann diese vera rbeiten. Wird eine Stecknadel berührt, so w ird die
139
Kapitel 5 Google Maps einbetten
Methode touchesßegan: wi thEvent des Pi n-Objekts aufgerufen und zur Änderung
der Anzeige herangezogen.
Die Implementierung dieser Funktion finden Sie in Pin.m und im folgenden Code. Sie prüft,
ob das aktuelle und das vorherige Ereignis dieselbe Position auf dem Bildschirm haben.
Dadurch wird sichergestellt, dass der Code in dieser Methode nicht ausgeführt wird, falls
der Benutzer den Finger über den Bildschirm gezogen hat.
HateinesolcheBewegungnichtstattgefunden,kümmertsich touches Bega n: wi t h Event
um zwei verschiedene Fä lle. Der erste liegt vor, wenn der Benutzer einmal auf die Steck
nadel tippt. Dabei soll die einfache Nachricht angezeigt werden, die zusammen mit dem
Ort von der JavaScript-Seite der Anwendung übertragen wurde. Dazu werden die Refle
xionsmöglichkeiten von Objective-C verwendet, um eine s i ngl e Touch-Nachricht an die
Stecknadel selbst zu senden.
AnstatteinendirektenAufrufdurchzuführen,wirddieNachrichtpe rfo rmSe 1 ecto r: wi t h
Object: afterDel ay an die Stecknadel gesendet. Dadurch kann zwischen einzelnem
und doppeltem Antippen unterschieden werden. Wie Zei le 13 zeigt, hat der Benutzer 0.4 sek Zeit, um einen Doppeltipp zu vollenden. Geschieht dies nicht, wird die erste Berührung
verarbeitet und die zweite als eigene Geste gewertet.
Tippt der Benutzer dagegen innerhalb des Grenzwerts von 0.4 sek zweimal auf die Steck
nadel, wird die Nachricht cance l Prev i ous PerformRequestWi thTa rget: se l ect
or: object übergeben, die die Übergabe der s i ngl eTouch-Nachricht abbricht. Dieser
Ansatz mit verzögerter Ausführung und Abbruch ist die übliche Methode, um zu bestim
men, ob ein einfaches oder doppeltes Antippen vorliegt.
Wird ein Einzeltipp erkannt, wird die Nachricht sing l eTouch übergeben und die kurze
Beschreibung der Stecknadel angezeigt. Bei einem Doppeltipp dagegen wird die Karte auf
die Position der Stecknadel zentriert und vergrößert.
1 - Cvoid)touchesßegan:CNSSet *)touches 2 withEvent:CU I Event *)event{ 3 UITouch * touch = [touches anyübject]; 4 CGPoint prevloc = [touch previous l ocationinView:sel f ] ; 5 CGPoint cur l oc = [touch l ocationinView:sel f ] ; 6 7 ifCCGPointEqua l ToPointCprev loc , curloc) ){ 8 NSU i nteger tapCount = [touch tapCount]; 9 switch (tapCount) {
10 case 1: 11 [se l f performSelector: 12 @se l ector(singl eTouch) 13 wi thObject:n i l afterDelay: .4]; 14 break;
140
15 16 17 18 19 20 21 22 23
24
25
26
27 28 29 30 31
32
33 34
35 36 37 38 39 40 41 42
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
case 2: [NSObject cancelPrev ious PerformRequestsWithTarget:self
selector:@selector(s i ngleTouch) object:nil];
II Zentriert auf die Stecknadel und vergrößer MESSAG E(@"double tap pin %i, %i",
l ocation.x, locat i on.y);
double l atüffset = ( location.y+42 )1 ((Ma pVi ew*)self .superv iew) . pixelsPerDeglatitude ;
double l ngüffset = ( location.x+10)1 ((Ma pView*)sel f.superv iew).pixelsPerDeglongitude ;
double l atitude = [ [( (MapV iew*)sel f . superview). northWest objectAt i ndex:OJ doub l eVal ue] -l atOffset;
double longitude = [[ (( MapView*)self .superview). northWest objectAt i ndex:1] doub l eVal ue] + l ngüffset;
MESSAG E(@" l atitude: %f l ongitude: %f northWest: %@", l atitude, 1 ongitude, ((MapView*)self. superview).northWest);
NSString *javaScriptCa ll = [ [NSString alloc] i nitWithFormat:@"zoomTo (%f, %f) " ,
l atitude, 1 ongitude];
NSString *mapDescription [((MapView*)self .superv iew) .webMapView
stringßyEva l uatingJavaScriptFromString: javaScriptCall ];
[( (MapView*)self . superview) setMaplat l ngFrameWi thDescr i ption: mapDescription];
[( (MapView*)self . superview) updatePin locations];
brea k; default:
brea k;
141
Kapitel 5 Google Maps einbetten
Dadurch, dass bei einem Doppeltipp auf eine St ecknadel oder die Karte die Ansicht zent
riert und vergrößert wird, erhöht sich der Nutzwert der Anwendung. Die Standardanwen
dung f ür Karten führt bei einem Doppelt ipp nur eine Vergrößerung durch, zentriert die
Karte aber nicht, wesha lb ein Benut zer danach gewöhnlich noch mit dem Finger über den
Bildschirm fahren muss, um die Gegend um den Ort anzuzeigen, der ihn int eressiert. Unse
re Beispielanwendung hat diese Einschränkung nicht.
Sie können auch St ecknadeln auf der Kart e durch Ziehen verschieben lassen. Dazu dient
die im folgenden Code gezeigte Methode touc hesMoved : wi th Event. Dies f unktioniert
ähnlich wie das zuvor gezeigte Verschieben in der Karte. Ein Unt erschied best eht darin, dass erneut die Nachricht cancel Pr evi ousPerformReq ues t sWi thTa rget : se l ect
or : object übergeben wird, damit nicht die kurze Beschreibung angezeigt wird, da die
Met hode t ouches ßegan vor t ouchesMoved aufgerufen wurde. Ohne diese Abbruch
nachricht würde die Beschreibung angezeigt und dann die Stecknadel verschoben, was
aber unschön aussieht .
1 - Cvoid) touchesMoved: CNSSet *)touches 2 wi th Event: CU I Event *)even t { 3 if( [ touches count ] == 1) { 4 5 [ NSObject cancel PreviousPerf ormRequestsWithTarget: sel f
se l ector :@se l ec t or(si ngl eTouch) object :n i l ] ; 6 moved = YES; 7 UITouch *touch = [ touches anyübject]: 8 CGPoi nt prev l oc = [ t auch previouslocationinView: se l f ] ; 9 CGPoi nt curloc = [ tauch l ocationinView: se l f] ;
10 doubl e t ouchDel t aX = cur loc . x - pr evloc. x ; 11 doubl e t ouchDel t aY = cur loc .y - pr evloc. y ; 12 [ se l f moveX :touchDel t aX andY :touchDel t aY] ; 13 MapVi ew l ocat ion maploc = se l f . l ocat ion ; 14 map l oc . x += t ouchDel t aX ; 15 map l oc .y += t ouchDel t aY ; 16 se l f . l ocati on = maploc ; 17 if(self . info != ni l ){ 18 19 20 21 22
142
se l f . info.hi dden = TRUE; se l f . info. l abel . text = @"Unknown " ;
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
Wie beim Verschieben der Karte werden zum Verschieben der Stecknadeln die aktuelle
und die vorherige Position herangezogen, um die Platzierung zu ändern. Beim Verschieben
der Karte ist die Position der Mittelpunkt dieser, beim Verschieben der Stecknadeln der
obere linke Anzeigepunkt der Stecknadel in x- und y -Koordinaten.
Da die St ecknadel anschließend nicht mehr f ür den ursprünglich angegebenen Ort auf
der Karte steht, ist die mit ihr verknüpfte Beschreibung wahrschein lich ungültig und wird
daher auf Unknown gesetzt. Wird die Beschreibung angezeigt, wenn der Benut zer mit
dem Ziehen beginnt, so wird sie geschlossen, damit die CPU beim Ziehen nicht sowohl die
St ecknadel als auch die Nachricht zeichnen muss. Dies geschieht in Zeile 18.
Das Attribut i nf o der Klasse Pi n dient zur Anzeige der kurzen Beschreibung, die vom
JavaScript-Tei l der Anwendung zur Verfügung gestel lt wird. Es handelt sich dabei um ein
I n foWi ndow-Obj ekt, das selbst eine U I Vi ew ist und als einziges Attri but l abe l aufweist.
Die Methode in i tW i th Fr ame : a ndDes c ri pt i on von I nf oWi ndow, die Sie im folgenden
Code sehen und in der Datei lnfoWindow.m in (LASSES: MAPVIEW finden, legt die Posit ion
der Beschreibung im Fenster sowie deren Inhalt fest. Das Benutzerschnittst ellenelement
zur Anzeige der Beschreibung ist ein U I Labe l .
- ( i d)i nitWithFrame : ( CGRect ) frame andDescription : ( NSSt r i ng* )description{
i f ( se l f = [ super i ni tWithFrame :frame]) [ se l f setßac kgroundCol or : [U I Col or bl ac kCo l or ] ] ; CGRect l abel Fr ame = CGRec t Ma ke(O , 0 ,
frame . size.wi dt h , frame . size.height ) ;
l abel = [[UI Label all oc ] i ni t WithFr ame : l abel Frame ] ;
l abel . text = description; l abel . backgroundCol or = [ UICol or cl earCol or] ; l abel . t ext Col or = [ UI Co l or wh iteCol or ]; l abel . t ext Al ignment = UI Te xt Al ignment Cent er ; [ se l f addSubview: l abel ] ; [ l abel r el ease];
return se l f ;
Durch die Verwendung von U I Labe l zur Anzeige der Beschreibung öffnen sich Ihnen eine
Menge Möglichkeiten. Sie können jet zt die Schriftart, die Ausrichtung, Größe, Farbe und
viele andere Attribut e setzen, z.B. auch Schatten. Es ist zwar möglich, den Text direkt zu
143
Kapitel 5 Google Maps einbetten
zeichnen, ohne U I Labe 1 zu nutzen, aber dazu sind mehr Codezeilen erforderlich. Durch
die Verwendung der vorgefertigten Klasse U I Labe 1 gewinnen Sie eine deutlich wartungs
freund lichere Anwendung.
Die drei Klassen MapVi ew, Pi n und I nfoWi ndow bilden das Ma pVi ew-Modul. Sie enthalten
den gesamten Quellcode, der zur Anzeige einer grundlegenden Google-Karte erforderlich
ist, lassen sich aber auf einfache Weise anpassen, um ein noch ausgefeilteres Verhalten zu
zeigen.
Beispielsweise können Sie die Klasse I nfoWi ndow so ändern, dass sie noch mehr Einzel
heiten anzeigt, indem Sie entweder die Anzeigegröße anpassen oder eine ganz andere
UIV i ew anzeigen, z.B. die normale Kartenanwendung von Apple. Sie können auch dafür
sorgen, dass die Klasse MapV i ewebensowie die Standardanwendung Routen anzeigt.
Seide Änderungen erfordern zwar Kenntnisse in Objective-C, sind technisch aber nicht
aufwendig.
Ein weiterer bemerkenswerter Punkt, den wi r bisher noch nicht behandelt haben, ist die
Frage, wie die Positionen der Pi n-Objekte und ihrer I nf oW i ndows beim Verschieben und
Vergrößern der Karte angepasst werden. Jede dieser Klassen verfügt über die Methode
moveX: andY, deren Parameter die Anzahl der Pixel in x- und y-Richtung sind, um die die
Stecknadel oder das Informationsfenster verschoben werden soll. Diese Methode sehen
Sie im folgenden Code.
Unerfahrene Objective-C-Programmierer mögen versucht sein, die Position durch eine
Codezeile wie [se l f frame ] . o r i gi n . x += xChan ge zu ändern. Diese Codezei le löst
keine Ausnahme aus, führt nicht zu einem Kompilierungsfehler - und ändert die Position
der Stecknadel oder des Informationsfensters nicht.
In U I V i ew-Kiassen von Objective-C, z.B. Pi n und In f oW i ndow, wird der Rahmen, der die
obere linke Ecke und die Länge und Breite festlegt, nur in zwei Fällen verwendet. Erstens
geschieht dies bei der lnitialisierung mit der Nachricht i ni tW i th Frame. in diesem Fa ll
w ird die als Parameter ent haltene Rahmenstruktur dazu verwendet, die Größe der Ansicht
zu ändern. Der zweite Fall tritt auf, wenn das Attributframe gegen ein anderes ausge
tauscht wird, w ie Sie in der Methode move X: andY sehen.
- ( voi d) moveX: (doub1e) xChange andY :( doub1 e)yChange { CGRect f rame = [ se1f frame ] ; frame.or i gin . x += xChange ; frame.or i gin .y += yChange ; se1f. frame = f rame;
Aufgrund dieser eingeschränkten Änderbarkeit hat die direkte Bearbeitung des Attributs
f r ameeiner Ansicht keinerlei Auswirkung.
144
Die Objective-C-Implementierung des Kartenmoduls von QuickConnect
Jedes Mal, wenn die Kartevergrößert oderverschoben wi rd,mussdie Methode mov eX: a ndY aufgerufen werden. ln der Methode touchesMoved :wi th Event der Klasse MapVi ew wird der Stecknadel diese Nachricht bei jedem erfassten Ereignis gesendet.
for(int i = 0; i < numPins; i++){ Pin *aPin = [pins objectAt l ndex:i]; [aPin moveX:touchDel taX andY:touchDeltaY]; [aPin . info moveX:touchDel taX andY:touchDeltaY];
Das Vergrößern der Karte erfolgt in der Methode touc hesEnded: wi thEvent der Klasse MapVi ew. Diese Nachricht wird vom Gerät an ein MapVi ew-Objekt gesendet, nachdem alle touchesßegan- und touchesMoved-Nachrichten verarbeitet wurden.
Im fo lgenden Code wird zunächst ermittelt, ob ein Doppeltipp vorliegt, und dann die Position bestimmt, an der auf die Karte getippt wurde. Anschließend folgt ein Aufruf der JavaScript-Funktion zoomTo, die wirzuvor im Beispiel zum Einzoomen auf eine Stecknadel gesehen haben.
1 - (voi d)touches Ended:(NSSet *)touches 2 withEvent:(U IEvent *)event{ 3 4 if(OKToTouch) { 5 UITouch *touch = [touches anyübject ]; 6 if ([touch tapCount ] == 2){ 7 II Zoomen und zentrieren 8 CGPoi nt cur l oc = [touch l ocation i nView:se l f]; 9
10 11 12 13
14
15
16
doub l e l atüffset curloc.ylsel f.pixel sPerDeglatitude; doub l e l ngüffset curloc.xlpixel sPerDeg l ongitude;
doub l e l atitude = [ [northWest objectAtindex:OJ doub l eVa l ue] - l atüffset;
doub l e l ongitude = [[northWest objectAt i ndex:1] doub l eVa l ue] + l ngüffset;
NSString *javaScriptCa ll =
[[NSString all oc] i nitWithFormat: @"zoomTo(%f, %f) " , l atitude, l ongitude];
NSString *ma pDescript ion = [webMapView stringßyEval uatingJavaScriptFromString: javaScri ptCa ll ];
17 18 [sel f setMa plat l ngFrameWithDescription:mapDescripti on ] ;
145
Kapitel 5
19 20
Google Maps einbetten
[ sel f updatePinlocationsJ:
21 el se t 22 NSLog(@"touched"); 23 24 25
Nachdem die Vergrößerungaufgrund des Doppeltipps auf ein Pi n-oder MapV i ew-Objekt durchgeführt worden ist, wird die Nachricht updatePi nlocat i ons an das MapV i ewObjekt gesendet, wie Sie in Zeile 19 des vorstehenden Codes sehen. Der folgende Code zeigt, wie durch diesen Aufruf die Positionen der einzelnen Stecknadeln anhand von deren Längen- und Breitenwert sowie des Vergrößerungsfaktors aktual isiert werden.
Als Maß für die Vergrößerung dienen die Attribute pi xe l sPerDeg l atitude und p i xe 1 s pe rDeg Long itude (Pixel pro Breiten- bzw. Längengrad) der Klasse Ma pVi ew, die im vorherigen Aufruf der Methode setMap Lat LngFrameWi t hDescri pt i on gesetzt wurden.
1 - (void) updatePin locationst 2 int numPins = [pins count ] ; 3 for(int i = 0: i < numPins; i++H 4 Pin *aPin = (Pin*) [pins objectAt l ndex:i J : 5 doub l e l atitudeDel ta = [ [northWest objectAtlndex:OJ
doub l eVa l ue] - aPin. l ocation. l atitude: 6 doub l e l ongitudeDel ta = aPin. l ocation. l ongitude -
[[northWest objectAtlndex: 1] doubl eVa l ue ] ; 7 8 doub l e yPixe l s = l atitudeDel ta * pixel sPerDeg latitude; 9 doub l e xPixel s = l ongitudeDel ta * pixel sPerDeglongitude;
10 MapViewl ocation aPin l ocation = aPin. l ocation: 11 aPinlocation.x = xPixel s - 10 - 4; 12 // Die sichtbare Stecknadel befindet sich zehn Pixel von 13 // l in ks im Bild 14 aPinlocation.y = yPixe l s - 42 + 10; 15 // Die sichtbare Stecknadel befindet sich zehn Pixel von 16 // unten im Bi l d 17 18 CGRect pinFrame = aPin.frame; 19 pinFrame.origin .x = aPin l ocation.x;
146
Zusammenfassung
20 pi nFrame . or i gi n. y = aPin l ocat ion .y ; 21 aPi n . f rame = pi nFrame; 22 aPin . l ocation = aP i n l ocati on : 23 24 CGRect i nfoFrame = aPi n . i nfo. frame: 25 i nfoFrame. or i gin. x = aP i nl ocat i on . x - 100: 26 i nfoFrame. or i gin. y = aP i nlocat i on .y - 30: 27 aPi n . i nfo. frame = i nf oFrame: 28 29
Wie in der Methode moveX : andY muss der Rahmen abgerufen, verändert und dann zu
rückgesetzt werden. Dies geschieht in den Zeilen 18 bis 22 des vorstehenden Codes für die
Steckn adel und in den Zeilen 24 bis 27 für das zugehörige I nfoW i ndow des Pi n-Objekts.
Die Positionen der einzelnen Pi n- und I nfoWi ndow-Objekte werden bei jeder Vergröße
rung angepasst. Dabei ist es möglich, dass einige nicht mehr innerhalb der Ma pV i ew sicht
bar sind, was j edoch kein Problem darstellt. Sie werden einfach im nicht sichtbaren Bereich
außerhalb des Bi ldschirms dargestellt . im Code müssen sie nicht ausgeblendet werden.
5.3 ZUSAMMENFASSUNG
in diesem Kapitel haben Sie gesehen, wie Sie Google-Landkarten in Ihre Anwendung
aufnehmen und ein Modul zur Kartenanzeige erstellen. Außerdem haben Sie gesehen,
wie Sie die Posit ionen von benut zerdefin ierten und St andardansichten bearbeiten.
Durch den wohl überlegten Einsatz von JavaScript -Aufrufen für eine Google-Karte, die
in einer U I WebV i ew angezeigt w ird, können Sie die JavaScript-API von Google zum Ver
größern und Zentrieren nutzen.
All dies ist im Fra mework QuickConnect enthalten, sodass Sie mit einem JavaScript-Auf
ruf eine vollständig verwendbare Google-Karte anzeigen können. Das Kartenmodul ist
nicht nur auf der JavaScript -Seite des Frameworks einfach zu verwenden, sondern auch in
Obj ective-C-Anwendungen, die Sie für das iPhone schreiben. Mehr als wen ige Zei len Code
ist dafür nicht erforderlich.
Benutzerdefin ierte, eingebettete Google-Karten liegen nun für Ihre iPhone-Anwendun
gen im Bereich des Möglichen. Version 3-0 von iPhone OS hat dies sogar noch einfacher
gemacht.
147
Datenbankzugriff
Die meisten auf JavaScript aufbauenden Anwendungen brauchen einen Webserver zum
Speichern von Daten. Mit iPhone OS 2 .0 oder höher und der Klasse U I WebVi ew können Sie
Daten ohne Netzwerkzugriff auf dem iPhone speichern. Das bedeutet, dass die Anwen
dung, die Sie erstel len, ein Bürger erster Klasse auf dem iPhone ist.ln diesem Kapitel lernen
Sie, wie Sie Daten speichern und abrufen und w ie Sie Datenbanken und Tabellen erstel
len. Sie erhalten hier einen einfach zu verwendenden JavaScript-Wrapper fü r die auf dem
iPhone verwendete SQLite-Datenbank. lm ersten Abschnitt geht es um die ersten Schritte
zur Verwendung der Datenbank, in den folgenden Abschnitten um den Wrappercode.
6.1 ABSCHNITT 1: DIE BEISPIELANWENDUNG
BRowsERDBAccEss
Das Beispiel BrowserDBAccess soll Ihnen zeigen, wie Sie Datenbanken in JavaScript
Anwendungen einsetzen können. Sie fi nden es im Verzeichnis Examples des QuickConnectFami(y-Ordners und können es von http:l/sourceforge.netlprojectslquickconnect/ herunterladen.
Diese Beispielanwendung erstellt die SQLite-Datenbank s amp l eDB mit derTabeile s co re.
Diese Datenbank befindet sich in der UIWebVi ew und erm öglicht dem Benutzer, Infor
mationen abzuf ragen. Auf diese Weise erstel lte Datenbanken verbleiben zwischen dem
Kapitel 6
Seenden und dem Neust art der Anwendung auf dem Gerät, auch wenn sie nicht mit
der Anwendung inst alliert wurden. Daher sind Dat en, die Sie in der Dat enbank abgelegt
haben, immer noch da, w enn Sie die Anw endung neu starten. Abbi ldung 6.1 zeigt die Bei
spielanwendung, bevor eine Abf rage an die Dat enbank gesendet wird.
DATENBANKEN , SO W EIT DAS Ä UGE REICHT
Für Datenbanken gibt es ein besonderes Vokabular. Zum Gruppieren ähnlicher Elemen
te werden Tabellen verwendet, und diese Elemente werden jewei ls als Datensätze an
gesprochen. Datensätze bestehen aus Werten, die in sogenannte Felder eingetragen
werden, und Felder wiederum sind durch ihren Namen und ihren Typ definiert. Wenn
Sie sich einen Datensatz als eine Zeile in einem Arbeitsblatt vorstellen und ein Feld als
eine Spalte, kommen Sie der Wahrheit schon recht nahe. Tabellen ähneln den Arbeits
blättern einer Tabellenka lkulationsanwendung. Wenn Sie in einer Datenbank einen
neuen Datensatz zu einer Tabelle hinzufügen, ähnelt das dem Vorgang, eine neue Zei le
in ein Arbeitsblatt einzufügen. Es ist nicht dasselbe, aber die Ähnlichkeiten sind stark
genug, um dieses Beispiel zum leichteren Verständnis heranziehen zu dürfen.
Ein Primärschlüssel ist etwas, das einen bestimmten Datensatz in einer Tabelle eindeu
tig bezeichnet. Es kann sich dabei um einen Integerwert oder um Text handeln, aber es
dürfen keine Duplikate auftreten. Der Primärschlüssel ähnelt der Kombination aus Be
nutzername und Kennwort für die Apple Developer Connection. Es wäre offensichtlich
von Übel, wenn zwei Personen dieselben Anmeldeinformationen hätten.
Ein Fremdschlüssel dagegen ist etwas völlig anderes. Er wird verwendet, um Daten
aus zwei verschiedenen Tabellen zu verknüpfen. Stellen Sie sich zwei Tabellen vor,
owners und dogs . Die Tabelle owners hat einen Primärschlüssel für jeden Daten
satz. Um deutlich zu machen, welcher Hund zu welchem Besitzer gehört, wird in die
Tabelle dogs ein Fremdschlüssel eingefügt, der den Primärschlüssel des Besitzers aus
der Tabelle owne r s enthä lt. Das ist so ähn lich wie die Registrierungsnummer auf der
Steuermarke des Hundes, mit der der Besitzer ausfindig gemacht werden kann, wenn l sein Hund im Tierheim landet.
150
SQLite-Datenbanken der WebKit-Engine verwenden
Wtbl<it Darabast Name: s.an1pleDB
SQL: SELECT • FROM scorc
~ Abbildung 6.1: Die Anwendung BrowserDBAccess vor dem Ausführen einer Abfrage
Die Tabellescore in der Anwendung Browse r DBAcces s besteht aus zwei Feldern. Das
erste ist ein Text-Primärsch lüssel namens pl ay er _name, das zweite ein Integerfeld
namens score. Das Primärschlüsselfeld wird nicht automatisch inkrementiert, weshalb
der Benutzer jedes Mal, wenn er einen Datensatz einfügt, einen Wert dafür angeben muss.
Die Anwendung B rowse r DBAcces s nutzt verschiedene vorgefertigte JavaScript-Kiassen,
-Methoden und -Funktionen, um auf die Daten in der Datenbank s amp 1 eDB zuzugreifen.
6.2 ABSCHNITT 2: SQLITE-DATENBANKEN DER WEBKIT
ENGINE VERWENDEN
Eine Datenbank verwenden zu müssen, mag manchmal einschüchternd wirken. Program
mierer und Ingenieure müssen an unzählige mögliche Fal lstricke denken, wenn sie Informa
tionen speichern oder abrufen. Nur zu oft ha lten diese möglichen Fal lstricke Programmierer
davon ab, Datenbanken für die einfache Datenspeicherung einzusetzen.
Auf dem iPhone werden Daten in und fü r Anwendungen standardmäßig in der eingebet
teten SQLite-Datenbank statt in Text- oder Binärdateien festgehalten. Die schnelle und
einfache Verwendung dieser Datenbank-Engine kann über den Erfolg Ihrer Anwendung
entscheiden. Um die Entwicklung zu besch leunigen, ist im QuickConnectiPhone-Frame
work eine entsprechende JavaScript-Kiasse ent halten, sodass Sie sich nicht um die Prob
leme bei der Verwendung von Datenbanken zu kümmern brauchen.
151
Kapitel 6
Die Datei DataAccessObjectjs, die Sie in der Gruppe QC i Phone sowohl in der Dashcode- als
auch in der Xcode-Vorlage finden, enthä lt einen Wrapper für den Code, der für den Zugriff
auf die SQLite-Datenbank erforderlich ist. Diese JavaScript-Datei wird sowohl durch die Dashcode- als auch die Xcode-Vorlage automatisch in die index.htmi-Datei Ihrer Anwen
dung aufgenommen. Dieser Wrapper, die Klasse Da taAccessObj ect, besteht aus einem
Konstruktor und mehreren Methoden. Die vier wichtigsten sehen Sie in Tabelle 6.1.
Attribut/Methode Rückgabewert Beschreibung Parameter
DataAccesOb- Da taAccess - Erstellt beim DbName- Ein String, der ject ( dbName, Object Aufruf mit dem die Datenbank eindeutig dbVersion, Sch lüsselwort bezeichnet dbDescript ion, new ein Da ta -
dbVers ion- Ein String, dbSi ze. AccessObject
der gewöhnlich die Form isNat iveDatabase)
einer Fließkommazahl
aufweist
dbDes cri pt ion-Ein
String, der den Zweck
der Datenbank angibt
dbS i ze- Der Mindest-
betrag an Festplatten-
platz in Byte, der der
Datenbank zugewiesen
wird . Wird NULLoder gar
nichts übergeben, be-
t rägt der Standardwert
5 MByte.
isNat iveDa tabase -
Ein Boole, der besagt, ob
es sich um eine native
(mit der Anwendung installierten) Datenbank
handelt
152
SQLite-Datenbanken der WebKit-Engine verwenden
getData CSO L . Keiner Die Methode ruft SOL- ein gült iger SQL-parameterArray) m it dem überge- Befeh lsstring
benen SQL-Code pa ramete rA rray- Ein
Informationen Array aus Werten, das
aus einer in der
UIWebView verwendet w ird, wenn es
sich bei dem SQL-Befeh l erstellten Daten-
um eine vorbereitete bank ab
Anweisung handelt
setData CSO L . Keiner Die Methode SOL- ein gültiger SQL-parameterArray ) speichert mit Befeh lsstring
dem übergebe-pa rame t erArray-
nen SQL-Code Ein Array aus Werten,
Informationen das verwendet wi rd,
in einer in der wenn es sich bei dem
UIWebView SQL-Befeh l um eine
erstellten Daten-vorbereitete Anweisung
bank handelt
getNat i veData CSOL. Keiner Die Methode ruft SOL- ein gült iger SQL-parameterArray) m it dem überge- Befeh lsstring
benen SQL-Code pa rame t erArray-
Informationen Ein Array aus Werten,
aus einer mit das verwendet wi rd,
der Anwendung wenn es sich bei dem
install ierten SQL-Befeh l um eine
Datenbank ab vorbereitete Anweisung
handelt
setNat i veData CSOL. Keiner Die Methode SOL- ein gült iger SQL-parameterArray) speichert mit Befeh lsstring
dem übergebe-pa rame t erArray-
nen SQL-Code Ein Array aus Werten,
Informationen das verwendet wird,
in einer mit der wenn es sich bei dem
Anwendung SQL-Befeh l um eine
i nsta liierten vorbereitete Anweisung
Datenbank handelt
Tabelle 6.1: Die wichtigsten vier Methoden von Da t aAcc essObj ec t
153
Kapitel6
Diese JavaScript-Wrapperklasse wird in der Datei databaseDefinitionjs verwendet, die
durch die Vorlage in Ihre Anwendung eingefügt wird.ln dieser Datei geben Sie an, welche
Datenbanken Ihre Anwendung nutzt.
Der folgende Code stammt aus der Datei databaseDefinitionjs der Beispielanwendung
BrowserDBAccess und zeigt, wie der Konstruktor eingesetzt wird, um eine Datenbank
zu erstellen, die von der in iPhone-Web-Apps verwendeten WebKit-Engine verwaltet wird.
Die integrierte Datenbankunterstützung der Engine können Sie verwenden, wenn alle er
forderlichen Daten von der Anwendung nach ihrer Installation generiert werden.
var sampl eDatabase = new DataAccessObject("sampl eDB" , "1.0", "a sampl e database", 2000);
Der vorstehende Code erstellt die Datenbank sampl eDB (oder öffnet sie, falls sie bereits
vorhanden ist). Da sich die WebKit-Engine um die Erstellung und Verwendung dieser
Datenbank kümmert, braucht sie einige Informat ionen. Die erste ist die Versionsnummer
der Datenbank, die Sie auf jeden beliebigen Wert setzen können. ln diesem Beispiellautet
er 1. 0. Die Datenbank wird außerdem mit einer Maximalgröße von 2000 Byte initial isiert.
Wäh len Sie hierbei die Größe aus, die Ihnen geeignet erscheint.
Der gezeigte Konst ruktor gibt ein Da taAccessObject zurück, das mit der zugrunde lie
genden SQLite-Datenbank verbunden und einsatzbereit ist. Änderungen an der Daten
bank sind jetzt möglich; ein Beispiel dazu finden Sie in dem folgenden Code, der zeigt, w ie
Sie die Methode set Da ta des DataAccessObj ect verwenden:
sampl eDatabase . setDataC " CREATE TABLE I F NOT EX I STS score C'p l ayer_name ' VARCHAR PRIMARY KEY, ' score' I NTEGER) ;");
Dieser SQL-Befehl dient dazu, die Tabelle zu erstel len, aber die Methode set Da ta können
Sie f ür alle SQL-Anforderungen verwenden, die Datenbanktabellen bearbeiten, Daten ein
fügen oder entfernen oder die Datenbank auf irgendeine Weise verändern.
Wie in Kapitel2, »Die Modularität von JavaScript f ür iPhone-Anwendungen«, beschrieben,
besteht ein Verwendungszweck von BCFs (Business Control Functions) darin, Daten aus
der Datenbank abzurufen. Die BCF getScores BCF (d ie im folgenden Code gezeigt wird)
erfü llt diese Aufgabe. Sie finden sie jeweils in der Dateifunctionsjs der Beispiele.
Diese BCF verwendet die Methode getData des DataAccessObj ect, um die Datensätze
aus der Tabelle score abzurufen. ln Zei le 3 sehen Sie den Aufrufvon getData.
1 function getScoresBCFCparameters) { 2 var SOL= ' SELECT * FROM score ' ; 3 sampl eDatabase.getDataCSQ L) ; 4
154
SQLite-Datenbanken der WebKit-Engine verwenden
Abbildung 6.2 zeigt die mit dieser BCF abgerufenen Daten. Beachten Sie, dass get
ScoresBC F nichts zurückgibt, da die Methode getData asynchron ist und daher die
Ergebnisse der SQL-Abfrage nicht zurückgibt. Das QuickConneetiPhone-Framework küm
mert sich um den Empfangder Daten und übergibt sie an dieSteuerobjekte,die demselben
Befehl zugeordnet sind wie die BCF. Die VCF (View Contra I Function) d i s p l aySco res VC F
in der Dateifunctionsjs ist demselben Befehl zugeordnet wie getScoresBC F, weshalb
das Framework die Informationen, sobald sie verfügbar sind, dieser VCF übergibt.
Wcl>Kil Dntal>as• Namt: sampl<OB
SQL: SELECT • FROM S<Ore
c~ .. Q~O')' > pJ.a)"i'r_n~nte u en bob 100
1000 jo~ S()()
sooo mgo 5SOO
This should really do some actual work!
~ Abbildung 6.2: Die Beispielanwendung BrowserDBAccess nach dem Antippen der Schaftjläche Execure QUERY
Das Einfügen von Daten in eine Tabelle läuft sehr ähnlich ab. Wenn ein Datensatz für eine
Personnamens Jane eingefügt werden soll, wird setData aufgerufen, wie Sie im Folgen
den sehen:
sampl eDatabase.setData( "I NSERT INTO score VALUES( 'bob', 100)");
Es ist nicht üblich, Werte in SQL-Anweisungen hart zu kodieren, denn gewöhnlich werden
die Werte durch den Benutzer eingegeben. Es ist zwar möglich, eine SQL-Anweisung wie die
vorstehende aus Benutzereingaben zu konst ruieren, aber das kann gefahrlieh werden. Der
folgende Code zeigt, wie Sie dieses Risiko mithilfe von vorbereiteten Anweisungen meiden:
func t ion setScoresBCF(parameters){ var name = document .get El ementßyld( ' nameFi eld').value; var score = document.get El ementßyld( ' scoreFiel d ' ) .va l ue; var StatementParamet ers = [ name , score]; var SO L = "I NSERT I NTO score VALU ESC? , ?) " ; samp l eDatabase . setData(SQ L , st atementParameters);
155
Kapitel 6
Dies sieht anders aus als der Auf ruf von setData zum Erst ellen der Tabelle scor e.ln dem
Tei l des SQL-Strings, in dem sich der Name und ein Punktestand befinden sollten, stehen
stattdessen Fragezeichen. Dabei handelt es sich um Platzhalter, die in vorbereitet en An
weisungen die Stellen markieren, an denen Dat en aus dem Array st atement Pa r amete r s
eingef ügt werden sollen. Der Programmierer ist daf ür verantwortlich, dass die Werte im
Array in derselben Reihenfolge plat ziert sind wie im SQL-St ring. Aus diesem Grunde st eht
die Variable name im Array sta t emen t Parameters vor score.
WAS SIND VORB ERE ITETE ANWEI SU N GEN?
Vorbereitete Anweisungen erhöhen dramatisch die Sicherheit von SQL zur Speiche
rung von Daten, die der Benutzer eingibt. Sie bi lden eine hervorragende Möglichkeit,
um SQL-Injektionsangriffe zu verhindern, und sollten viel häufiger eingesetzt werden,
als es der Fall ist.
Nehmen wir an, Sie möchten einen Datensatz in die Tabelleuser _preferences ein
fügen, die über die Felder l ocati on, co l o r und song verfügt. Das könnten Sie wie
folgt tun:
" SELECT * FROM user _p r eferences WH ERE name = "+aN ame
SQL-Anweisungen auf diese Weise zusammenzubauen ist jedoch schlecht. Es kann
nicht oft genug betont werden, wie schlecht das ist, denn dadurch öffnen Sie die
gesamte Datenbank für sogenannte SQL-Injektionsangriffe. Stückeln Sie SQL-Anwei
sungen nicht zusammen!
Die sichere Vorgehensweise besteht darin, einen SQL-String wie den folgenden zu er
stellen:
" SELECT * FROM user_pr eferences WH ERE name = ? "
Dazu erstellen Sie ein Array mit den Werten, die anstelle der Fragezeichen verwendet werden sollen. Die Aufrufe von set Da ta und get Da ta kümmern sich um den Rest, da
sie eine vorbereitete Anweisung verwenden.
Bei der Verwendung einer vorbereiteten Anweisung wird der SQL-Code ana lysiert,
bevor die Fragezeichen durch die Werte ersetzt werden. Falls also in irgendeiner der
Variablen schädlicher SQL-Code entha lten ist, wird er also gar nicht erst ana lysiert. Für
die Datenbank sieht es so aus, als enthalte die SQL-Anweisung einen merkwürdigen
String. Ein Aufruf mit Fragezeichen wie der vorstehende gibt keine Ergebnisse zurück,
der zusammengestellte dagegen kann alles mögliche aus einer Tabelle zurückgeben, l was der Hacker sehen möchte.
156
Nat ive SQlite-Datenbanken verwenden
Vorbereitete Anweisungen schützen Datenbanken vor Eindringversuchen über SQL-Injek
tionsangriffe. Es mag zwar unsinnig erscheinen, diese kleine Datenbank gegen Eindring
linge zu schützen, aber das ist es nicht. Es gibt immer die Möglichkeit, dass j emand, der
keinen Zugriff auf ein Gerät oder den darauf ausgeführten Code haben soll, dort Schaden
anrichtet. Datenverarbeitung sollte stets auf sichere Weise erfolgen.
Auch das Entfernen von Daten aus der Datenbank läuft nach diesem Muster ab. Da hier
bei die Datenbank geändert wird, muss die Methode setDa ta verwendet werden. Aus
Sicherheitsgründen wird auch hier eine vorbereitete Anweisung verwendet, da der Benut
zer einen Namen angibt, der entfernt werden soll.
function del eteScoreBC F( pa r ameters ){ var name = document .getEl ementByld( ' nameFi el d').value; var StatementParameters = [ bl ogName ] ; database . setData( ' OELETE FROM score where name = ? ',
statementParameters);
6.3 ABSCHNITT 3: NATIVE SQLITE-DATENBANKEN VERWENDEN
Sie können Datenbanken nicht nur in derWebKit-Engine erstellen und verwenden, die sich in jeder i Phone-Web-App finden lässt, sondern auch native Datenbanken einsetzen. Da bei
kann der Entwickler bereits vorhandene Daten in die insta llierte Anwendung aufnehmen.
Nehmen w ir an, Sie schreiben eine Anwendung, die Benutzern helfen soll, Waren in einem Großmarkt zu finden, und möchten darin eine Reihe von GPS-St andardorten auf nehmen.
Anstatt die Daten beim Start der Anwendung herunterzuladen und zu speichern, können
Sie sie in einer SQLite-Datenbankdatei in die Insta llation der Anwendung auf nehmen.
Die Beispielanwendung nat i veDBAccess hat die gleiche Funktion wie BrowserDBAc
cess, verwendet aber die SQLite-Datenbank sample.sqlite. Abbi ldung 6.3 zeigt diese Datei
in der Gruppe RESOU RCES im Xcode-Proj ekt.
Der JavaScript-Code zum Erstellen eines Da taAces s Obj ect, das als Wrapperfür den Aufruf
einer nativen Datenbank f ungiert, unterscheidet sich von dem fü r die WebKit-Datenbank aus Abschn itt 2. Wie bei der WebKit-Datenbank erfolgt die Definition in der Datei datbaseDefinitionjs. Bei nativen Datenbanken ist jedoch nur der Name der Datenbankdatei erfor
derlich, während die Parameter fürVersion und Größe überflüssig sind, da die Größe nativer
Datenbanken unbeschränkt ist (innerhalb sinnvoller Grenzen) und die Versionssteuerung
bei der Erstel lung und Verteilung durch den Besitzer der Anwendung erfolgt.
var sampl eData base = new Da ta Ac cessObject ( "sampl e . sq l ite") ;
157
Kapitel 6
Beachten Sie, dass es keinen Aufruf zum Erstellen einer Tabelle gibt, da die Tabelle sco r e
bereits in der Datei sample.sqlite vorhanden ist. Es ist zwar möglich, in nativen Datenbanken
Tabellen zu erstellen, aber dies ist eher unüblich. Die Tabellen werden der Datenbankdatei
gewöhnlich hinzugefügt, bevor die Anwendung in den App Store von Apple eingestellt w ird.
Q()f) !::J nativeDBAccess C)
I (Project Setting) I Debug · I ~ ~. ~ (Q.. Strlng Matehing ) OvOIView Action Bulld Bulld and Go Tasks Info Surch
Groups & Flies 111'1 jflle Name • I o<;. jCode I 0 I A t G I ,. rl:J natlveDBAccus ~ [j sample.sqllte Ii!
,.CJo;mes . ,.. CJ Other Sources
• CJ Resources ijJ databoseDeftnltlonJ > .i!J functlon>.J> ~ lndex.html i!J mai n.js
~ mapplng>.J> sample.sqllte
,.CJ MapView ,.. CJ QCIPhone
,. CJ Pms ,.CJ images
lfiJ MainWindow.)(i b
~ lnfo.pllst Dashcode to Xcode.o
,.. D Framewerks ,.. CJ Products
[D d lst.pllst ,.@>Targets
1> 0 El<ecutables • l!t Errors and Warnings
"' Q, Flnd Results
~1 l> lJ!]Bookmarks
~> § SCM -,.. Abbildung 63: Die Ressourcen für die Beispielanwendung nativ eDBAcce s s
Der Abruf von Daten aus einer nativen Datenbank erfolgt fast genauso w ie bei einer
Datenbank, die von der WebKit-Engine verwa ltet wird. Den einzigen Unterschied sehen
Sie im folgenden Code: Anstelle der Methode getData verwenden Sie getNat i veDa ta.
Für den Ersteller der Anwendung verhalten sich die beiden Methoden identisch.
function getScoresBC F(parameters ){ debug( ' gett ing scores from database' ) ; var SOL= ' SELECT * FROM score '; sampl eDatabase.getNativeData(SQ L) ;
Ebenso w ie die in Abschnitt 2 behandelte Methode getData ist auch getNat i veData
asynchron. Wenn die erfassten Daten verfügbar sind, übergibt das Framewerk sie daher
an andere Steuerobjekte, die demselben Befehl zugeordnet sind wie die BCF. Wie beim
WebKit-Beispiel ist dies die VCF d i s p l aySco res VC F.
158
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
ln Abbildung 6-4 sehen Sie die Anzeige, die diese VCF in der Beispielanwendung na t ive
DBAccess hervorruft.
Das Hinzufügen und Entfernen von Daten sowie Änderungen an der Datenbank erfolgen
genauso wie in Abschnitt 2, wobei nur die Methode setNati veData anstelle von set
Da ta verwendet wird. Wenn Sie eine Anwendung erstellen, sollten Sie keine Unterschiede
im Verha lten sehen.
Nadre Datab ase Name: sampl<.sqllt<
SQL: SELECT • FROM score
( fuCIIIe011(1'-, )
pla~·tr_namt scort bob 100
100()
jo:oc SOO
iqW' $50()
Tbis sltould really du some aclual work!
~ Abbildung 6.4: Die Beispielanwendung na t i veDBAccess
nach dem Antippen der Schaltj/äche OPEN DATABASE AND
EXECUTE QUERY
6.4 ABSCHNITT 4: DAS DATAÄCCESSÜBJECT IN DATENBANKEN
DER WEBKIT-ENGINE VERWENDEN
ln den bisherigen Abschnitten haben Sie gesehen, wie Sie das DataAccessObject ver
wenden, um sich nicht mit allen Einzelheiten der SQLite-lmplementierungen in der Web
Kit-Engine und in nativen Datenbanken beschäftigen zu müssen. ln diesem Abschnitt
erfahren Sie, was fü r Einzelheiten das sind und wie Sie sie nutzen. Wenn Sie einfach nur
Da t aAccessObject verwenden möchten, aber nicht das Bedürfnis haben zu erfahren,
wie es funktioniert, können Sie diesen Abschnitt überspringen.
Die Kl asse DataAcessObject in der Datei QCiPhone!DataAccessObjectjs ist dazu da,
dass der Programmierer oder Entwickler so wen ig von SQLite verstehen muss wie mög
lich. Daher wurde diese Klasse so entworfen, dass ihre Methoden und Konstruktaren so
sehr dem AJAX-Wrapper Se rverAccessObj ect ähneln wie möglich, der in Kapitel7, »Da-
159
Kapitel 6
tenzugriff über das Netzwerk«, behandelt wird. Durch die Vereinfachung der API können
Programmierer, die mit SQLite nicht vert raut sind, Daten speichern, ohne erst viel Neues
lernen zu müssen.
ANONYME FUN KTIONEN
Wenn eine Person anonym ist, heißt das, dass Sie ihren Namen nicht kennen. Ist eine
Funktion anonym, so hat sie keinen Namen. ln JavaScript wird der Name einer norma
len Funktion in einer Zeile w ie der folgenden deklariert:
f unc t ion bark(){ }
Der Name der Funktion lautet hier bark. Muss einer Funktion eine andere übergeben
werden, so wird häufig eine Funktion ohne deklarierten Namen verwendet, also eine
anonyme Funktion.
Die Übergabe einer anonymen Funktion an bark sieht wie folgt aus:
bark (new funct ion() { II Hi er tu t di e Fun kt i on irgendet was
} ) ;
Beachten Sie, dass der Bereichsoperator für die anonyme Funktion, I } , in den Parameteroperatoren der Funktion ba r k, ( ) , eingesch lossen ist. Die Funktion ba r k kann diese
Funktion jetzt nach Bedarf aufrufen und speichern.
Alle anonymen Funktionen haben Zugriff auf lokale Variablen, die der Funktion, in der
sie deklariert sind, übergeben werden können. Daher ist der folgende Code gültig:
St ring type= ' doberman ' : bark (new f unct ion() {
if(type == ' boxer ' ){
} ) ;
}
el se if(type == ' doberman ' ){ }
Diese Besonderheit ist praktisch, wenn Funktionen oder Methoden andere Funktionen als
Parameter verwenden, wie Sie weiter hinten in diesem Abschnitt noch sehen werden.
Wie jedes andere wertvolle Werkzeug sollten Sie auch anonyme Funktionen nicht
übermäßig einsetzen, also nicht dort, wo sie gar nicht nötig sind.
160
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
Der Konstruktor von Da taAcces sübj ect ist die einfachste Methode dieser Klasse. er soll
die Methoden des Objekts festlegen und als anonyme Funktionen definieren. Es werden also
keine Attribute gebraucht, um die dem Konstruktor übergebenen Parameter zu speichern.
Wie Sie in Tabelle 6.1 und in den Abschnitten 2 und 3 gesehen haben, verfügt Da taAc
cessübject über zwei Gruppen von Methoden. Die eine handhabt Daten, die in einer
WebKit-Datenbank gespeichert oder von dort abgerufen werden, die andere kümmert
sich um die Datenübertragung zwischen der JavaScript-Anwendung und einer in der ver
teilten Anwendung enthaltenen SQLite-Datenbankdatei. Die WebKit-Methoden weisen
den umfangsreichsten JavaScript-Code auf und werden als Erste aufgeführt.
Sowohl getData als auch setData sind nur Fassade. Diese Methoden führen nur sehr
wenig Berechnungsarbeit durch und greifen für die Hauptarbeit auf eine dritte Methode zurück. Die einzigen Berechnungen, die in diesen beiden Methoden stattfinden, betreffen
die Zusammenstellung der Werte, die in derVariablenpass Th rough Parameters gespei
chert werden (siehe den folgenden Code).
t hi s .getData = funct i on(SQL, preparedStatementParameters) { var passThroughParameters =
generatePassThroug hParamet ers(); this.dbAccess(SQ L, preparedStatementParameters.
fa l se , passThroughParameters) ;
Da das für die HTML s-Spezifikation verantwortliche Standardisierungsgremium W3C
verlangt, dass alle Aufrufe der Datenbankfunktionen der WebKit-Engine asynchron sind,
müssen zusammen mit den Anforderungen auch Informationen über den aktuellen
Status der Anwendung für den späteren Gebrauch übergeben werden. Die Funktion ge
ne ratePass Th rough Parameters aus QCUtilitiesjs erfasst die benötigen Werte.
Wie der folgende Code zeigt, gehören dazu der Befehl, für den Befehlsobjekte aufgerufen
werden, die Anzah l der bereits aufgerufenen BCOs, die an alle Steuerfunktionen übergebenen Parameter, z.B. globa l Pa ramAr ray, und ein Array mit den durch Aufrufe an ande
re BCFs hervorgerufenen Ergebnissen, z.B. global BCFResul ts.
function generatePassThroughParameters(){ var passThroughParameters = new Array(); passThroughParameters.pus h(window . curCmd ) ; passThroughParameters.pus h(window.numFuncsCalled ) ; passThroughParameters.pus h(gl obalParamArray); passThroughParameters.pus h(window.globalBCFResul ts ) ; return passThroughParamet ers;
161
Kapitel 6
Diese Werte werden später vom Framewerk verwendet, um sicherzustellen, dass übrig ge
bliebene Steuerfunktionen auf der Grundlage der in mappingsjs für den curCmd-Befehl
defin ierten Zuordnungen so ausgeführt werden, als wären alle Aufrufe von Befehlsfunk
tionen synchron erfolgt. Weitere Erläuterungen dazu erhalten Sie in Kapitel 2.
Das resu ltierende Array pas sTh roughParameters wird zusammen mit einem Flag an
die Methode d bAcces s übergeben, wobei das Flag anzeigt, ob der SQL-Code in der Varia
blen SOL als Versuch zur Änderung der Daten in der Datenbank behandelt werden soll.ln
der Methode getData wird, wie wir bereits gesehen haben, fa l se übergeben.
Die Methode dbAccess ist das Herzstück der Klasse DataAccessObject für WebKit
Datenbanken. Sie erledigt die gesamte Arbeit, wenn getDa t a oder setData aufgerufen
werden.
Um die Methode dbAcces s verstehen zu können, müssen wir zunächst mit der zugrunde
liegenden JavaScript -API f ür SQLite vertraut werden. Diese API ist im kommenden Stan
dard HTML 5 enthalten und wird durch die Verwendung derWebKit-Engine in U IWebVi ew implementiert. Dies findet sich in allen iPhone-Web-Apps und in Mobile Safari wieder.
Die j üngste Version dieses Standards (zur Zeit der Drucklegung) fi nden Sie unter http:! I dev.w3.orglhtmlsfwebdatabase!. Dieses Dokument beschreibt verschiedene Obj ekte und
Objektmethoden, wie die folgenden Tabel len zeigen.
Das grundlegende Element der API ist das Database-Objekt. Tabelle 6.2 beschreibt eine
Funktion, die mit diesem Obj ekt in Zusammenhang steht, und eine seiner Methoden.
Bei openData ba se handelt es sich um eine Factory-Funktion, die ein Da tabase-Objekt
instanzi iert .
Attribut/Methode Rückgabewert Beschreibung Parameter
openData - Da ta ba se- Eine Factory- dbName- Ein String, der base(dbName, Obj ekt Funktion, die die Datenbank eindeutig dbVersion, ein Da tabase- bezeichnet dbDescr ipt ion, Objekt für die
dbVers ion- Ein String, dbSi ze) spätere Verwen-
der gewöhnlich die Form dungerstel lt
einer Fließkommazahl
aufweist
162
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
{Fortsetzung) dbDes cr i pt i on- Ein
String, der den Zweck der
Datenbank angibt
dbSi ze - Der Mindest-
betrag an Festplattenplatz
in Byte, der der Datenbank
zugewiesen wird. Wird
NULLoder gar nichts
übergeben, beträgt der
St andardwert s MByte.
tran sact ion ( exe- SO LTransa c- Eine Methode, execut ionCal l bac k -cuti onCa l l ba ck , t i on-Objekt die ein SO L- Eine Funktion mit erforder-
er ro rCa l l back, Transa cti on- lichem Code zum Ausfüh-successCal l ba ck ) Obj ekt für Ak- rung des SQL-Befehls
tua I isieru ngen er r or Ca ll back- Eine op-
und Abf ragen t ionale Funktion, die beim
von Datenban-Fehlschlagen der Transakti-
ken erstellt on aufgerufen w ird. in die-
ser Methode werden keine
Rollbacks der Datenbank
durchgef ührt, da bei einem
Fehler automatisch ein
Rollback erfolgt.
successCa l l ba ck - Eine
optiona le Funktion, die
beim erfolgreichen Ab-
schlussder Transakt ion
aufgerufen wird.
Tabelle 6.2:AP/jür Da t a ba se-Objekte
Nach dem Dokument fü r den Standard sind alle Parameter von openData base optiona l,
doch ist es unklug, keinen Datenbanknamen zu deklarieren. Wenn Sie in versch iedenen
Anwendungen mehrere Datenbanken einsetzen, sollte jede davon einen eindeutigen
Namen tragen. Den Parameter dbName nicht anzugeben, kann dazu führen, dass alle Ihre
Anwendungen dieselbe Datenbank verwenden - die dann auch schädlichen Anwendun-
163
Kapitel 6
genvon anderen Autoren zur Verfügung stehen kann. Um Ihre Datenbanken zu schützen,
wird etwas Ähnliches verwendet wie die Regel vom identischen Ursprung, die AJAX-Aufrufe
in Browsern einschränkt.
Die Schutzregel für Datenbanken ist eine Einschränkung, die verlangt, dasseine Datenbank
nur für Anwendungen mit demselben Ursprung zugänglich ist. Wenn eine Webanwen
dung von www. i hre_seite. de bedient wird und eine andere von web. i hre_ seite.
de, so wären die Datenbanken in diesen Anwendungen jeweils von beiden Anwendungen
aus zugänglich. Mit anderen Worten, alles, was von i hre_ sei te. de bedient wird, kann
auf alle Datenbanken mit diesem Ursprung zugreifen, und zwar unabhängig davon, ob die
Datenbank von der laufenden Anwendung erstellt wurde oder von einer Anwendung, die
von einer anderen Unterdomäne von i h re_sei te. de angelegt wurde.
Bei Web-Apps verwenden Sie ein U I WebV i ew-Objekt statt eines Webbrowsers, weshalb es
keine Regel des identischen Ursprungs zur Einschränkung von AJAX gibt. Es ist zurzeit noch
nicht geklärt, aber kann angenommen werden, dass auch die Ursprungsbeschränkung für
Datenbanken unwirksam ist. Der einzige Schutz Ihrer Datenbanken vor dem Zugriff durch
andere Anwendungen besteht daher möglicherweise darin, dass die Autoren dieser ande
ren Anwendungen den Namen und die Version Ihrer Datenbank nicht kennen. Achten Sie
daher darauf, Ihren Datenbanken einen Namen und eine Versionsnummer zu geben.
Die Methodetransaction wird von allen SQL-Aufrufen verwendet. Tatsächlich gibt es
keine Möglichkeit, SQL-Code in einerWebKit-Datenbank auszuführen, als die Verwendung
eines von transactionerstellten SO L Transact i on-Objekts. Daher sind alle JavaScript
Datenbankaufrufe in iPhone-Web-Apps automatisch transaktionssicher.
Häufig beunruhigt Entwickler die Frage, wann ein Rollback in der Datenbank erfolgen soll.
Gewöhnlich ist dies der Fall, wenn der vom Programmierer geschriebene Code feststellt,
dass eine Transaktion auf irgendeine Weise feh lgeschlagen ist. Wenn Sie die JavaScript
Datenbankfunktionen verwenden, müssen Sie sich um Rollbacks nicht kümmern, da
Transaktionen bei einem Feh lschlag automatisch einen Rollback durchführen.
Senden Sie nicht die SQL-Anweisu ng ROLL BACK, wenneine Transaktionfeh lsch lägt, dennfür
den Rollback ist bereits gesorgt, sodass durch eine solche Maßnahme nur Probleme verur
sacht werden. Die an die Methodetransaction übergebene Fehlercallback-Funktion wird
nicht für diesen Zweck verwendet, sondern nur zur Benachrichtigung über Feh lsch läge.
DasSOLTrans a ct i on-Obj ekt hat nur eine Methode, nämlich exec uteSO L (siehe Tabe lle
6.3). Diese Methode nimmt jeden SQL-Befehl entgegen, den Sie ihr senden. Es ist jedoch
unklug, eine SQL-Anweisung zusammenzustellen und dann auszuführen. Stattdessen
sollten Sie vorbereitete Anweisungen nutzen. Wenn Sie nicht wissen, was das ist und wie
Sie sie einsetzen, schlagen Sie in Abschnitt 2 nach.
164
6.4 I Das DataAccessObject in Datenbanken der WebKit-Englne verwenden
Attribut/Methode Rückgabewert Beschreibung Parameter
executeSQL(sqlState - Void Eine Metho- sql Statement - Ein ment . arguments , de, die jeden String, der eine gültige successCallback , beliebigen SQL-Anweisung ent-errorCallback) String einer hält. Er kann ?-Sym-
SQL-Anweisung boleals Platzhalter
ausführt enthalten, wenn er als
vorbereitete Anwei-
sung behandelt wi rd.
ar gument s -Ein
optiona les Array der
Werte, die die ? -Plat z-
halter in vorbereiteten
Anweisungen ersetzen.
successCal lback -Eine opt iona le Funk-
tion, die bei erfolg-
reicher Ausführung
der SQL-Anweisung
aufgerufen wird.
errorCallback -
Eineoptionale Funk-
tion, die aufgerufen
w ird, wenn die Aus-
führungder SQL-An-
weisung fehlsch lägt.
Tabelle 6-3: API eines SOL Tra ns a ct i on-Objekts
Neben der SQL-Anweisung w ird ein optionaler Parameter mit Argument en übergeben,
nämlich ein Array aus Strings, durch die j egl iche in der SQL-Anweisung vorhandenen
Fragezeichen ersetzt werden sollen. Dabei handelt es sich um die Va riablen in einer vor
bereiteten Anweisung, die durch einen Aufrufvon executeSQ L erstellt w urde. Ein Aufruf
dieser Methode legt stets eine vorbereitete Anweisung an, selbst wenn es keine Platz
halter gibt. Wenn Sie vorbereitete Anweisungen verwenden, gewinnen Sie Sicherheit. Wenn nicht, geht es auch nicht schneller.
165
Kapitel 6
Die letzten beiden Parameter sind Callback-Funktionen, die ausgeführt werden, wenn die
Anweisung- nicht die Transaktion!- feh lschlägt oder erfolgreich ausgeführt wird. Der
Erfolgsfunktion übergibt die Methode executeSOL ein SO LResu l tSet-Objekt. Die API
dieses Objekts sehen Sie in Tabelle 6-4. Der Fehlerfunktion dagegen wird ein SO LE rror
Objekt übergeben (mit der API aus Tabelle 6.6). Um das Ergebnis der Ausführung der SQL
Anweisung handhaben zu können, müssen Sie diese Funktionen implementieren und in
den Aufruf der Methode executeSO L einschließen.
Attribut / Methode Rückgabewert Beschreibung Parameter
insertiD Keiner Ein schreibgeschütztes Integer- Keine
attribut, das die ID eines eingefügten Datensatzes enthält, falls das ID-Feld
automatisch inkrementiert wird
rowsAffected Keiner Ein schreibgeschütztes Integer- Keiner
attributmit der Anzahl der Zei len, die
durch eine Aktual isierungsanweisung
hinzugefügt oder geändert werden
rows Keiner Ein SO LRes ul tSetRowL i st -Attribut Keiner
mit allen resultierenden Zei len einer
Abfrageanweisung
Tabelle 6.4: API eines SO LRes u 1 tSet-Objekts
Das SO LResul tSet -Obj ekt enthält die Informationen, die Sie mithilfe der SQL-Anwei
sung abgefragt haben, sowie zwei zusätzliche prakt ische Elemente, nämlich die Attribute
i nsert i D und rowsAffected.
Wenn Sie einen Datensatz in eine Tabelle mit einem automatisch inkrement ierten Primär
schlüssel einfügen, enthält dasAttributins e rt I 0 des SO LRes u l tSet-Objekts den auto
matisch generierten Schlüsselwert. Das ist praktisch, wenn Sie den Sch lüssel brauchen,
um damit verknüpfte Daten in andere Tabellen einzufügen.
Nach einer erfolgreichen Einfüge- oder Aktualisierungsanweisung enthält das Attribut
rowsAffected die Anzahl der eingefügten oder geänderten Zeilen. Dies kann zur Über
prüfung des Verhaltens komplexer SQL-Anweisungen verwendet werden.
Das dritte Attribut von SO LResu ltSet ist rows. Es enthält SO LResultSet RowL i st, einen
Wrapper fü r den Zugriff auf ein Array aus Datensätzen. Wie Sie in Tabelle 6.5 sehen, hat die
ses Obj ekt das Attribut l ength, das die Anzahl der Datensätze im Ergebnis einer SELECT
Anweisung enthält. Diese Zah l entspricht der Anzahl der Zeilen im eingebetteten Array.
166
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
Attribut / Methode Rückgabewert Beschreibung Parameter
length Keiner Ein schreibgeschütztes Integer- Keine attributmit der Anzahl der Da-
tensätze, die durch eine Abfrage-
anweisungabgerufen wurden
item( i ndex) Array Eine Methode, die einen Daten- index-Die
satzals assoziatives JavaScript- Nummer des
Array oder als Map zurückgibt Datensatzes im
Resultset, der
zurückgegeben
werden soll
Tabelle 6.5: API eines SO LRes u 1 tSetRowL i s t-Objekts
Das Objekt hat auch die Methode i t em f ür den Zugriff auf einzelne Ergebniszeilen. Mit
dieser Methode und dem Attribut können Sie in eingebetteten tor-Schleifen sehr leicht
durch die Zeilen und Werte iterieren. Die Standardvergehensweise dafür sehen Sie in dem
folgenden Code:
1 for ( var i = 0: i < aResul t Set .l eng t h; i ++){ 2 var aRow = aResul tSet. i t em(i); 3 for( key i n aRow){ 4 var aVal ue = aRow[key ]; 5 //H ier wird etwas mi t dem Schl üssel und dem Wer t get an 6 7
Den Code dieser fo r -Schleife würden zwar viele als Standardvergehensweise betrachten,
doch wird er nicht optimal ausgeführt, da in Zeile 1 die Länge des Resultsets jedes Mal
abgerufen w ird, wenn der Code die äußere Schleife durchläuft. Verschwendung zeigt sich
auch in der w iederholten Verwendung der fo r - ea eh-Sch leife in Zeile 3-
for - eac h-Schleifen in JavaScript sind vor allem verschwenderisch, was CPU-Zyklen an
geht, vor allem aber, wenn sie in anderen Sch leifen auftreten. Weiter hinten in diesem
Abschnitt erfahren Sie bei der Erläuterung der Methode dbAccess, wie Sie diesen Code
so ändern können, dass er besser ausgeführt wird.
Tritt bei der Ausführung der SQL-Anweisung irgendeine Art von Feh ler auf- z.B. aufgrund
eines Fehlers in der Anweisung-, w ird statt eines SQLResul tSet- ein SQ LE rror-Objekt
erstellt. So w ie das SQLResul tSet-Objekt der Erfolgsmethode übergeben wi rd, die als
Parameter der Methode executeSQ L für die Anweisung angegeben ist, so geht das
SQLError-Objekt an die Fehlerfunkt ion.
167
Kapitel 6
Der Erfolgsfunktion wi rd niemals ein SQLError-Objekt übergeben und der Fehlerfunk
tion niemals ein SQLResul tSet. Beide Funktionen dienen jeweils nur einem einzigen
Zweck, sodass sie einfacher zu schreiben und zu warten sind.
Das SQ LError-Objekt enthält zwei Attribute fü r die Fehlercodenummer und die von
SQLite generierte Fehlermeldung (siehe Tabelle 6.6).
Attribut/ Methode Rückgabewert Beschreibung Parameter
code Keiner Ein schreibgeschütztes Attribut mit der Feh- Keine
lernummer. Folgende Werte sind möglich:
o- Die Transaktion sch lug aus unbekannten
Gründen fehl.
1-Die Anweisung schlug aus unbekannten
Gründen fehl.
2- Die Anweisung schlug fehl, da die erwar-
tete Version der Datenbank nicht mit der
tatsächlichen übereinstimmt.
3- Die Anweisung schlug fehl, da zu viele
Daten zurückgegeben wurden. Versuchen Sie
den SQL-Modifizierer LI MI T zu verwenden.
4 - Die Anweisung sch lug fehl, da das Spei-
cherlimit erreicht w urde und der Benutzer
der Erhöhung des Grenzwerts nicht zuge-
stimmt hat.
5- Die Anweisung schlug aufgrundeines
Sperrenfehlers in der Tra nsaktion feh l.
6- Eine I NSERT-, UPDATE- oder REP LA CE-An-
weisungschlug fehl, da sie eine Einschränkung
verletzt hat (z.B. durch Duplizierung eines ein-
deutigen Schlüssels).
message Keiner Ein schreibgeschütztes Attribut mit der ent- Keine
sprechenden Fehlermeldung
Tabelle 6.6: API eines SOLE r ro r -Objekts
168
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
Die beiden Elemente code undmessagesind f ür Programmierer und Entwickler zwar
hilfreich, sollten dem Benutzer aber nicht angezeigt werden, der damit ohnehin nichts
anfangen kann. Verwenden Sie diese Indikatoren, um den Feh ler aufzuzeichnen und dem
Benutzer eine hilf reiche Meldung anzuzeigen.
Beispiele dafür, wie diese Objekte verwendet werden, finden Sie in der Methode dbAccess
von DataAccessObj ect.Wie in diesem Abschnitt bereits erwähnt, hat diese Methode fünf
Parameter und erledigt die eigentliche Arbeit hinter der Fassade der beiden Methoden get
Data und setDa ta. Der vierte Parameter gibt an, ob der Zugriff angefordert wird, um die
Datenbank zu ändern oder sie abzufragen. Dieser Parameter wird von der Fassadenfunktion
festgelegt, die dbAccess aufruft.
Bei der Untersuchung der Methode dbAccess stoßen Sie auf mehrere anonyme Funktio
nen. Die erste wird in Zeile 5 als erster und einziger Parameter an die Methode transac
t i on der Datenbank übergeben. Es mag einfacher erscheinen, diesi rgendwoanders im
Code als reguläre Funktion zu defin ieren und als ersten Pa ra meter zu übergeben, aber das
würde den restlichen Code problematisch, wenn nicht sogar unmöglich machen- Variablen, die sich im Gült igkeitsbereich befinden, wei l sie anonyme Funktionen verwenden,
wären dann nämlich nicht mehr im Gültigkeitsbereich. ln Zeile 2 des nachfolgend gezeig
ten Codes wird das Oue ryRes u l t -Objekt instanzi iert, das als Rückgabewert der Methode
dbAccess dient.
Damit ein OueryRes ul t -Obj ekt wirklich nützlich sein kann, muss es innerhalb der Funk
tion exec uteSql der Transaktion verfügbar sein. Außer der Verwendung anonymer Funk
tionen besteht die einzige Möglichkeit hierf ür darin, es global zu machen.
Bei globalem Gültigkeitsbereich wäre j edoch immer nur ein Datenbankzugriff auf einmal
möglich. Da aber der gesamte Datenbankzugriff asynchron erfolgt, kann dies unmögl ich
garantiert werden. Der beste Ansatz besteht also darin, anonyme Funktionen zu verwen
den. Diese Logik gilt auch fü r die Funktionen, die an die Methode executeSq l der Trans
aktionselbst übergeben werden.
Der Methode executeSql des Transaction-Objekts können zwei Funkt ionen als
Parameter übergeben werden. Es ist eine bewährte Vorgehensweise, dies stets zu tun. Die
zweite Funktion, die Sie in Tabelle 6.3 als dritten Parameter sehen, ist die Funktion, die das
Ergebnis der Abfrage handhaben soll, wenn al les gut geht. Die Deklarat ion dieser Funk
tion beginnt in Zei le 10 des folgenden Codes.
in der Erfolgsfunktion wird eine vom SQL-Code generierte ID für einen eingefügten
Datensatz in dem OueryResul t -Obj ekt gespeichert, das in Zeile 7 instanzi iert wird.
Wurden Zeilen in der Datenbank geändert, so wird auch die Anzahl der betroffenen Zeilen
bestimmt. Dies geschieht jedoch nur, wenn der Parameter t rea t AsCha ngeData der
Methode dbAccess auf t rue gesetzt it.
169
Kapitel 6
Wurden keine Daten geändert, so folgt daraus, dass eine Abfrage ausgeführt wurde. Dieser Fall wird in den Zeilen 23 bis 51 behandelt. Hier wird ein zweidimensionales JavaScriptArray erstellt und an den QueryResul t -Rückgabewert angehängt. Es speichert al le Daten, die im SOLRes u l tSet gefunden wurden. Durch die Übertragung der Daten an ein JavaScript-Standardarray kön nen Sie im restlichen Code auf die Daten zugreifen, ohne die Struktur des SQLResul tSet-Objekts oder die von der Abfrage zurückgegebenen Felder kennen zu müssen. Für den Fall, dass Sie die Namen der Felder doch brauchen, werden sie für den späteren Gebrauch im Que ryRes u l t-Objekt gespeichert. Die Feldnamen und die Feldwerte bleiben in derselben Reihenfolgewie im SQLResul tSet-Objekt.
1 this.dbAccess = function(SQ L, preparedStatementParameters. 2 treatAsChangeData, passThroughParameters){ 3 if ( !this.db) { 4 this.db = openDatabase (dbName. dbVersion. 5 dbDescription. dbSize); 6 7 var queryResul t = new QueryResul t ( ); 8 this .db.transaction ( function(tx ) { 9 tx .executeSql CSO L. preparedStatementParameters.
10 function (tx. resu l tSet) { 11 if(treatAsChangeData ){ 12 try{ 13 queryResul t . insertediD = resul tSet . insertld; 14 queryResul t . rowsAffected =
15 resu l tSet. rowsAffected; 16 17 18 19 20 21 22 23 24
25 26 27 28 29 30
170
catch(ex ){
el se{
II Es muss sich um eine Aktual isierung handel n queryResul t . rowsAffected =
resu l tSet.rowsAffected;
II Die Datenbank wurde nicht geändert . II Es muss sich um eine Abfrage handel n. queryResul t.numRows Fetched =
resul tSet . rows . l ength; var dataArray = new Array () ; queryResul t.numResul tFie l ds = 0; queryResul t.fiel dNames = new Array () ;
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
Das DataAccessObject in Datenbanken der WebKit-Engine verwenden
i f (queryResul t.numRowsFetched > 0){ II Fel d-IDs aus dem Resu l tset abrufen var firstRecord = resu l tSet . rows . item(O); var numFi elds = 0; for(key in f irstRecord){
queryRes ult.fiel dNames.push(key); numFiel ds++;
queryResul t.numResultFie l ds = numFiel ds ; var numRecords =
queryRes ult .numRows Fetched; for(var i = 0; i < numRecords; i++ ){
var record = resu l tSet.rows.i tem(i); var row = new Array(); dataArray. push(row); for(var j = 0 ; j < numFie l ds; j ++){
row . push( record [queryResul t.fieldNames [ j] ] ) ;
queryResul t.data = dataArray;
if(window.cal 1Func){ var theResul ts = new Array() ; theResul ts.pus h(queryResul t ) ; theResul ts.pus h(passThroughParameters); requestHand l er(passThroughParameters[OJ.
54 55 56 57 58 59 60
passThroug hParameters[2 ], theResults);
61 }II Ende der Erfo l gs -Ca l l backfunkt ion zur SOL -Ausführung 62 . function(tx. error) { 63 queryResul t.errorMessage = error.message; 64 i f(window.ca l l Func){
var theResul ts = new Array() ; theResul ts.pus h(queryResul t ) ; theResul ts.pus h(passThroughParameters); requestHand l er(passThroughParameters [OJ .
65 66 67 68 69 passThroug hParameters[2 ], theResults ) ;
171
Kapitel 6
70 } 71 II Ende der Haupt feh l erfunktion der SOL- Ausführung 72 ); II Ende des Haupt aufrufs von executeSq l 73 }); II Ende der Transakt ions-Ca l l backfunkt ion 74 II Ende der Methode dbAccess
Unabhängig davon, ob die ausgeführte SQL-Anweisung die Datenbank ändert oder ab
fragt, wird das zu Beginn des Funktionsaufrufs erstellte Oue r yRes u l t -Objekt vom Frame
werk an alle restlichen, noch nicht aufgerufenen Funktionen verteilt. Dies geschieht in
den Zeilen 58 und 59 mit der in Kapitel2 vorgestellten Funktion requestHand l er.
Zeile 62 zeigt den Anfang der Deklaration fü r die Fehlerbehandlungsfunktion der Metho
de des Trans a ct i on-Objekts. Diese Funktion ist dafür zuständig, die von SQLite generier
te Fehlermeldung in das OueryResul t -Objekt einzufügen und dieses dann an die rest
lichen Steuerfunkt ionen zu übergeben. Weitere Informat ionen über solche Funkt ionen
erhalten Sie in Kapitel 2.
6.5 ABSCHNITT 5: DATAÄCCESSÜBJECT IN NATIVEN
DATENBANKEN VERWENDEN
Für den Zugriff auf nat ive Datenbanken ist weniger JavaScript -Code erforderlich als f ür
den aufWebKit-Datenbanken. Die meiste Arbeit wird im Objective-C-Teil des Framewerks
erledigt.
Wie die im vorhergehenden Abschnitt beschriebenen Methoden getData und setData
sind auch getNat i veDa ta und setNat i veDa ta nur Fassaden. Jedoch rufen Sie nicht die
Methode dbAcces s von Da taAcces sübj ect auf, sondern die Funkt ion getDev i ceDa ta
aus der Datei comjs.
this . getNativeData = funct ion(SQL , preparedStatementParameters){
getDeviceData(dbName , SO L, preparedStatementParameters);
this . setNativeData = funct ion(SQL , preparedStatementParameters){
setDeviceData(dbName, SO L, preparedStatementParameters);
Die Funktion getDev i ceDa ta besteht aus zwei Hauptfunktionseinheiten. Die erste, die
Sie im folgenden Code in den Zeilen 4 bis 16 sehen, stel lt ein Array aus Informationen
zusammen, die zum Ausführen der Abfrage in Objective-C erforderlich sind. ln diesem Array befinden sich auch die im vorhergehenden Abschnitt besprochenen, durchgereich-
172
DataAccessObject in nativen Datenbanken verwenden
ten Parameter. Sie sind hier vonnöten, da diese Anforderung ebenso wie die an eine Web
Kit-Datenbank asynchron erfolgt. Weitere Informationen über asynchrone Datenverarbei
tung finden Sie in Kapitel 2.
Das Array enthält den Datenbanknamen, den auszuführenden SQL-Code, eventuell von
diesem Code benötigte Parameter für vorbereitete Anweisungen sowie durchgereichte
Paramet er. Informat ionen über vorbereitete Anweisungen finden Sie im vorhergehenden
Abschnitt dieses Kapitels.
1 f uncti on getDev iceData ( dbName. SOL. 2 pr epa r edStatementPa r ameters . call BackParams ){ 3 i f (dbName && SQL ){ 4 va r dataArray = new Array () ; 5 dat aArray .push( dbName ) ; 6 dataArray .push( SQL) ; 7 if ( preparedStatementParameters ){ 8 dataArray .push(preparedStatement Parameters ) ; 9
10 el se{ 11 // I n ei nen Pl atzhal ter ei nfügen 12 dataArray .push( new Array()) ; 13 14 va r ca l l ßa ckParameters = 15 gener atePassThr oughParameter s () ; 16 dataArray .push(cal l ßac kPa r ameters ) ; 17 18 var dataString = JSON.stringify(dataArray) ; 19 makeCal l ( " getData " . dataSt ri ng ) ; 20 21 return nul l : 22
Nachdem die Daten vorbereitet sind, werden sie in einen JSON-String umgewandelt und
an die Funktion ma keCa l l übergeben. Diese Funktion löst den Obj ective-C-Teil des Frame
werks aus, w ie Sie in Kapitel4, »GPS, Beschleunigungsmessung und andere systemeigene
Funktionen von QuickConnect«, gesehen haben. Dies ist die zweite größere Funkt ionsein
heit . Ohne sie wäre kein Zugriff auf native Datenbanken mögl ich. Weitere Informationen über JSON finden Sie in Anhang A, »Einf ührung in JSON«.
Wie die Funktionen in Kapitel4 zum Zugriff auf systemeigene Daten werden zum Abrufen
der Daten aus der Datenbank Objective-C-Steuerobjekte gebraucht. Je nachdem, ob die Da
tenbank verändert oder abgefragt wird, w ird das Objekt SetData BCO bzw. GetDa taBCO ein
gesetzt. Dies entspricht der Verwendung der JavaScript-Funktionen getData und setData.
173
Kapitel 6
+ (id) doCommand:CNSArray*) parameters {
OuickConnectViewController *control l er = COuickConnectViewControll er*) [parameters objectAtlndex:O J :
if( [ parameters count] >= 3){ NSString *dbName = [parameters objectAtlndex:l]: NSString *SOL= [parameters objectAtlndex:2 ] : NSArray *perparedStatementVa l ues = ni l : if( [parameters count ] >= 4){
perparedStatementVa l ues = [parameters objectAt l ndex:3]:
SO LiteDataAccess *aDBAccess = CSOLi teDataAccess*)[controll er.databases
objectForKey:dbNameJ:
if(a DBAccess = ni l ){
aDBAccess = [[SOLiteDataAccess al l oc] in i tWit hDatabase:dbName isWriteabl e: YESJ:
[controll er .databases setObject: aDBAccess forKey:dbNameJ:
return [aDBAccess getData:SQ L with Parameters:perparedStatementVa l ues];
return ni l :
@end
Wie die JavaScript-Funktionen get Data und setData führen auch diese BCOs wenig Berechnungsarbeit durch. Im vorstehenden Code ruft die Methode doComma nd den Datenbanknamen, den SQL-Code und eventuelle Parameter für vorbereitete Anweisungen ab, die in der JavaScript-Anforderung übergeben wurden.
Wenn diese Informationen zur Verfügung stehen, wird die Methode getData des SO Li teDataAccess-Objekts aufgerufen. Dieses Objekt entspricht im Großen und Ganzen einem DataAccessObj ect inJavaScript. Es verfügtebenfalls über Methodennamens s etDa ta und getDa ta, doch die Objective-C-Version ist im Gegensatz zur JavaScript-Version ein Singleton. Wenn Sie mehr über Singletons wissen wol len, lesen Sie Kapitel4.
174
DataAccessObject in nativen Datenbanken verwenden
Die Methoden getData und setData von SOLi teDa taAcces s sind wie ihre JavaScript
Entsprechungen Fassaden f ür die Methode dbAccess. Wie die JavaScript-Methode dbAc
cess ist auch die Objective-C-Version ziemlich kompl iziert, was am Umfang der SQLite
API für die dynamische Bibliothek libsqlite3.o.dylib liegt, die mit jedem iPhone und iPod
tauch ausgeliefert wird. Diese API sehen Sie in Tabelle 6.7.
Objekt/Funktion Rückgabewert Beschreibung Parameter
sq l i te3 Keiner Eine Objektdarstellung Keine
der SQLite-Datenbank im
Arbeitsspeicher
sq l i te3_open SQLI TE_OK Öffnet die Datenbank im fi l ePath - Der ( filePath , bei erfolg- angegebenen Dateipfad vol lständige pfad &a Database ) reichem und speichert den Zeiger zur SQLite-Daten-
Öffnen in aDatabase dateiauf dem Gerät
aDatabase-Eine
Zeigerreferenz
auf einen SQLite3-
Zeiger, der für eine Datenbank im Ar-
beitsspeicher steht
sq l i te3_cl os e voi d Schließt die Verbindun- aDatabase-Ein ( aOatabas e ) gen zur SQLite-Daten- SQLite3-Zeiger, der
bankdatei in der Funktion
sq l i te3_open
gesetzt wird
sq l i te_ er rms g con st Ruft den letzten aDatabase-Ein ( aOatabase ) cha r * generierten Fehler ab SQLite3-Zeiger auf
die Datenbank, von der eine Fehler-
meldung abgeru-
fen werden sol l
sq l i te3_stmt Keiner Eine einzelne vorbe- Keine
reitete SQL-Anweisung
175
Kapitel 6
sql i te3_ i nt Interpretiert den aDatabase- Ein
prepare_ v2 SOL ite_OK
SQL-Code SQLite3-Zeiger auf ( aDatabase.
bei Erfolg die Datenbank
SO LCha r. SO LCha r-Ein
- 1, &s t ate-cons t char
ment. NU LU * -Typ der UTF8-
Zeichen, die den
SQL-String bilden
sql i te3_ int Zählt die Felder im statement-Ein
co l umn_count Resultset einer Abfrage sq l ite3_ stmt-(s t atemen t ) Zeiger
sql i te3_ const Ruft den Namen eines statement- Ein co l umn_name char * Feldes ab sq l i t e3_stmt -(s t atemen t . i ) Zeiger
i-Ein Integerfü r
die Feldnummer
sq l i te3_ i nt Ruft die Anzah l der aDatabase- Ein
changes Datensätze ab, auf die SQLite3-Zeiger auf (a Database) sich die Änderung einer die Datenbank
Tabelle auswirkt
sq l i te3_ st eps i nt Verschiebt die Einfüge- statement-Ein (s t atemen t )
SOLITE_ROW marke im Resultset zum sq l i t e3_stmt -
bei verfüg-nächsten Datensatz Zeiger
barer Zeile
sql i te3_ i nt Ruft den Typ eines Feldes statement-Ein
co l umn_type Mögliche
(Spalte) im Resu ltset sq l i t e3_stmt -(s t atemen t . i )
Werte: einer Anweisung ab Zeiger
SOLI TE_ i -Die Nummer
I NTEGER des Feldes, von dem
Daten abgerufen SO LI TE_ LOAT werden sollen
SOLITE_BLOB
SOLITE_NU LL
SOLI TE_ TEX T
176
DataAccessObject in nativen Datenbanken verwenden
sql ite3_ i nt Ruft den Wert eines statement-Ein
co lumn_int Integerfeldes ab sq l i te3_stmt-(sta tement, i ) Zeiger
i -Die Nummer
des Feldes, von dem
Daten abgerufen
werden sollen
sql ite3_ double Ruft den Wert eines statement-Ein column_doub l e doubl e-Feldes ab sq l i te3_stmt-
(sta tement, i ) Zeiger
i -Die Nummer
des Feldes, von dem
Daten abgerufen
werden sollen
sqlite3_ const Ruft den Wert eines statement-Ein co lumn_text unsigned Stringfeldes ab sq l i te3_stmt-(sta tement, i ) char * Zeiger
i -Die Nummer
des Feldes, von dem
Daten abgerufen
werden sollen
sqlite3_ byte * Ruft die Bytes eines statement-Ein co lumn_bl ob BLOß-Feldes (Binary sq l i te3_stmt-(sta tement, i ) Large Obj ect) ab Zeiger
i -Die Nummer
des Feldes, von dem
Daten abgerufen
werden sollen
sql ite3_ int Ruft die Anzahl der statement-Ein co lumn_bytes Bytes im Wert eines sq l i te3_stmt-(sta tement, i ) BLOß-Feldes ab Zeiger
i -Die Nummer
des Feldes, von dem
Daten abgerufen
werden sollen
177
Kapitel 6
sqlite3_ void Ruft die mit der Anwei- statement-Ein
finalize sung verknüpften sq l ite3_stmt-(statement) Ressourcen ab Zeiger
sqlite3_ i nt Bindet einen Zeiger auf statement-Ein
bind - bl ob ein Byte-Array an einen sq l ite3_ stmt-(statement, Platzhalter in einer vor- Zeiger parameter l ndex, bereiteten Anweisung
parameterlndex aVariable,
-Die Indexnummer bytelength,
des Platzhalters in transcienceKey )
der vorbereiteten
Anweisung
aVariab l e-Ein
Zeiger auf das Byte-
Array, das in der
Datenbank gespei-
chert werden soll
byte Length- Der
Anzah l der zu spei-
ehernden Bytes
transcienceKey
-Ein Indikator dafür,
ob die einzufügen-
den Daten vorher
kopiert werden so I-len, um zu verhin-
dern, dass sich die
Daten während der
Speicherung ändern
sq l ite3_ bind_ i nt Bindet einen doub l e-Typ statement-Ein doub l e(statement, an einen Platzhalter in sq l i te3_stmt-parameter l ndex, einer vorbereiteten Zeiger aVariab l e) Anweisung
178
DataAccessObject in nativen Datenbanken verwenden
{Fortsetzung) paramet er l ndex - Die lndexnum-
mer des Platzhal-
ters in der vorberei-
teten Anweisung
aVa r i abl e - Ein
doub 1 e-Wert, der
in der Datenbank
gespeichert
werden soll
sq l i te3_bind_ i nt Bindet einen Integer sta temen t -Ein int ( statement, an einen Platzhalter sq l i te3_stmt-
pa r ameterlndex, in einer vorbereiteten Zeiger aVar i abl e) Anweisung
parameter l ndex -Die lndexnum-
mer des Platzhal-
ters in der vorberei-
teten Anweisung
aVariab l e-Ein
Integer, der in der
Datenbank gespei-
chert werden soll
Tabelle 6-7= Die SQLLite3-API
Diese ( -Bibliothek enthält alle Funktionen, die für den Zugriff auf SQLite-Datenbanken
erforderlich sind, sowie zusätzliche Merkmale wie Transaktionen und vorbereitete Anwei
sungen. Der folgende Code, der aus der Methode dbAccess des SO Li teDataAccess
Obj ekts stammt, zeigt, wie Sie die API einsetzen, um mit vorbereiteten Anweisungen zu arbeiten. Wie in der Tabelle zur API aufgefüh rt, müssen der Funktion sq l i te3_p repa
re_v2 ein Zeiger auf die Datenbank, die auszuführende SQL-Anweisung sowie ein Zeiger
auf die Va riable sq l i te3_ stmt übergeben werden. Tritt während der Ausführung der
SQL-Anweisung ein Feh ler auf, gibt sq l ite3_ prepa r e_v2 einen numerischen Fehler
code zurück.
179
Kapitel 6
int numResultColumns = 0; sqlite3_stmt *statement = nil; const char* SQLChar = [SOL UTFBString]; if Csqli te3_prepare_v2C database, SO LChar, -1.
&statement, NU LL) == SQ LITE_O K) (
Die in dem vorstehenden Code übergebene Variable sql i te3_stmt wird bei der Ausfüh
rung der Funktion sq l i te3_p repa re_v2 gesetzt und enthält die SQLite3-Anweisung, die
anschließend verwendet wird, um die einzelnen Datenelemente aus dem Resultset einer
ausgeführten SQL-Abfrage abzurufen. Durch die einzelnen Aufrufe der Funkt ion sq l i te3_
s tep wi rd eine Einfügemarke verschoben, die die Zeilenposition im Resultset markiert.
Wenn das Resultset leer ist, also keine Zei len enthä lt, gibt sql i te3_step also nicht
SQLI TE_ ROW zurück, sondern SOLI TE_DONE. Dadurch können Sie eine whi l e-Anweisung
verwenden, um die Daten aus der Zei le abzurufen, auf die die Einfügemarke zeigt.
whi l e Csq l i te3_s tep(statement) == SOL I TE_ROW) (
in dieser whi l e-Schleife w ird eine Folge von NSMutab l eArrays erstellt, wie Sie in Zei le
232 der Datei SQLiteDataAccess.m und in der folgenden Zeile sehen. Jedes dieser Arrays
steht für eine Zeile mit abgerufenen Ergebnissen und wird daher row genannt.
NSMutabl eArray *row = [[NSMuta bl eArray al loc ] in i tWithCapacity:numResu l tCo l umns];
Die Aufrufe, mit denen die einzelnen Felder aus den Datensätzen des Resultsets gewon
nen werden, müssen jeweils so erfolgen, dass die Daten mit dem korrekten Typ abgerufen
werden. in Tabelle 6.7 finden Sie die verfügba ren Funktionen für die verschiedenen Typen.
Im folgenden Code werden alle diese Funktionen aufgerufen.
i nt type = [ [ [ theResu l t co l umnTypes ] objectAtlndex:i] i ntVa l ue];
i f(type == SOL I TE_I NTEGER) (
180
NSNumber *aNum = [ [ NSNumber al l oc] i nitWi thlnt: sq l i te3_column_int(statement, i)] ;
[ row addObject:aNum] ; [ aNum autorelease] ;
DataAccessObject in nativen Datenbanken verwenden
else if(type == SQLITE_FLOAT){ NSNumber *aFl oat = [ [ NSNumber alloc ]
initWithFl oat :sqlite3_column_double(statement. i )J;
[row addObject:aFloat]; [aFl oat autorel ease];
else if(type == SQLITE_TEXT){ NSString *aText = [[NSString al loc]
initWithCString:sqli te3_col umn_text(statement. i) encoding:NSASC II String Encoding];
[row addObject:aText ]; [aText autorelease];
el se if( t ype == SQ LITE_B LOB){ NSData *aData = [ [NSData al l oc]
dataWithßytes:sql ite3_col umn_bl ob(statement. i) l ength: sql ite3_col umn_bytes(statement,i)];
[ row addObject:aData]; [aData autore l ease];
el se{// SQ LITE_NU LL [ row addObject:@"nul l "];
Um jeweils die richtige Funktion aufzurufen, muss der Typ des betreffenden Feldes bestimmt werden. Dazu werden die Feldtypen vor diesen Aufrufen ermittelt und gespeichert, wie Sie in den Zei len 213 bis 220 der Datei SQLiteDataAccess.m und im folgenden Code sehen:
NSMut ab l eArray *col umnTypes = [ [NSMutableArray al l oc ] initWithCapacity:OJ:
for(int i = 0: i < numResultCol umns; i ++){ NSNumber * col umnType = [NSNumber numberWithi nt:
sql ite3_col umn_t ype(statement,i)]; [col umnTypes addObject:col umnType];
[theResul t set Col umnTypes:col umnTypes];
[col umTypes re l ease ];
181
Kapitel 6
Der Typ der einzelnen Spalten wird mit der Funktion sq l ite3_ col umn_ type vom
Resultset der Anweisung abgerufen. Der Funktion werden der Anweisungszeiger und die
Nummer des Feldes übergeben, dessen Typ bestimmt werden soll, woraufhin sie einen
numerischen Indikator für den Feldtyp zurückgibt. Möglich sind folgende Werte:
> SQL I TE_INTEGER
> SQLITE_FLOAT
> SQLITE_BLOB
> SQLITE_NUL L
> SQLITE_TEXT
DerRückgabetypderMethoden dbAccess,setData und get Data istein Da taAcce s s Res u l t
Zeiger. Dieses Objektenthält das Ergebnis der Ausführungeines beliebigen SQL-Strings in einer
SQLite-Datenbank. Derfolgende Code stammt aus der Datei DataAccessResult.h und zeigt die
Felder, die zum Speichern der Ergebnisse einer SQL-Abfrage verwendet werden.
@interface DataAccessResul t : NSObject { NSArray *fiel dNames; NSArray *co l umnTypes; NSMutabl eArray *resul ts; NSString *errorDescription: NS i nteger rowsAffected; NS i nteger inserted i D:
@property (nonatomic, retain) @property (nonatomic, retain) @property (nonatomic, retain)
NSArray *fiel dNames; NSArray *columnTypes; NSMutabl eArray *results;
@property (nonatomic, retain) NSString *errorDescr i ption: @property (nonatomic) NSinteger rowsAffected; @property (nonatomic) NSinteger inserted i D:
- CNSString*) JSONStringify;
@end
Da sich das Framework, wie schon in Kapitel4 besprochen, um die Datenübergabe küm
mert, sind in den an die VCOs (View Control Objects) gesendeten Parametern auch al le
DataAccessResult-Obj ekte entha lten, die durch Aufrufe des SOL iteDataAccess
Objekts erstellt wurden. Weil der Aufruf zum Festlegen oder Abrufen von Daten in der
nat iven Datenbank von JavaScript ausgeht, müssen die Endergebnisse der Abfragen
zurück an die JavaScript-Anwendung übergeben werden. Dies geschieht mithilfe des
SendDBResul tVCO-Objekts.
182
DataAccessObject in nativen Datenbanken verwenden
Wie al le Befehlsobjekte hat auch SendDBResul tVCO eine doCommand-Methode. Da die
Daten zurück an JavaScript übertragen werden müssen, werden die Ergebnisse in einen
JSON-String konvertiert. ln den Zeilen 8 bis 12 des folgenden Codes sehen Sie, w ie dies
geschieht. Jedes Ergebnis wird zunächst in einen JSON-String umgewandelt und dann
dem NSMutabl eArray namens retVa l hinzugefügt. Dieses Array w ird dann in einen
JSON-String konvertiert. Aufgrund von Einschränkungen in der JSON-Bibl iothek von
Objective-C ist ein Aufruf zum Erstel len eines JSON-Strings aus einem Array von Objek
ten nicht möglich. Die JSON-Bibliothek reicht nicht aus, um Objekte in Arrays korrekt zu
konvertieren. Daher ist für jedes DataAcces s Res ul t -Objekt ein zusätzlicher Aufruf von
JSONStri ngi fy erforderl ich.
1 + (id) doCommand:(NSArray*) parameterst
2 NSMut abl eArray *ret Va l = [[NSMutabl eArray all oc] ini t]; 3 NSArray *resul ts = [ parameters subarrayWithRange:aRange ] ; 4 int numResul t s = [ resu l t s count]; 5 for(int i = 0; i < numResults; i ++){ 6 DataAccessResul t * aResul t = 7 (Oa t aAccessResul t *)[resul ts objectAtlndex:i]; 8 NSString* resu l t String = [ aResul t JSONStringi fy ]; 9 [retVa l addObject:resul t String] ;
10 [aResu l t re l ease ] ; 11 12 [ re t Va l addObject:[ [ paramet ers object Atlndex: 4 ]
object Atlndex:O JJ : 13 14 SBJSON *generator = [ SBJSON al l oc ] ; 15 NSError *error ; 16 NSSt r i ng *da t aString = [ genera t or st r i ngWithObject:
retVa l error:&error ];
17 [ re t Va l re l ease ] ; 18 [ genera t or re l ease ]; 19 dataString = [ da t aString 20 st r i ngßyRepl acingOccurrencesOfString:@" ' "
wit hSt r i ng:@" \\ '" ] ; 21 dataString = [ da t aString
183
Kapitel 6
22 stringByRepl ac i ngOccurrencesOfString :@"&" withString:@"\\&" J:
23 NSString *jsStr ing = [ [NSSt r i ng all oc] 24 i nitWithFormat : 25 @" handl eRequestCompl et i onFromNat i ve( ' %@ ' ) 26 • data String]; 27 QuickConnectViewControl l er *contro l ler 28 parameters objectAtlndex :OJ: 29 [controller.webView 30 stringßyEva l uatingJavaScriptFromString:jsString]);
31 [jsStr ing re l ease]; 32 return ni l : 33
Wie in Kapitel 4, wo die Ergebnisse in einen JSON-String konvertiert wurden, erfolgt auch hier
ein Aufruf, der sie zur weiteren Verarbeit ung zum JavaScript-Teil der Anwendung übergibt. Da
bei handelt es sich um den zuvor gezeigten Aufrufvon s tri ngßy Eva l uat i ngJa v a Scr i pt
FromSt r i ng. Er f ührt die JavaScript-Funktion hand l eRequestComp l et i on FromNat i ve
aus, die sicherstellt, dass die restlichen BCOs und VCOs dem ursprünglichen Befehl zugeordnet
sind. Zusammenfassung
Das JavaSc:ript-Modul DataAcces sObj ect macht die Interaktion mit SQLite-Datenbanken in der WebKit -Engine bedeutend einfacher. Da das Modul nur JavaScript-Stan
dardtypen wieStrings und Arrays akzeptiert, lässt es sich einfacher aufrufen als die SQLite
JavaScript-Funktionen der WebKit-Engine selbst. Da taAcces sObj ect fungiert außerdem als Fassade f ür den Zugriff auf »native« Datenbankdateien, die Sie zusammen mit Ihrer
Anwendung ausliefern können. Der Zugriff auf die Daten in diesen Datenbanken ist mit
JavaScript-Aufrufen möglich. Dadurch wird eine JavaScript-Anwendung so ausgereift, als
hätten Sie sie in Objective-C geschrieben.
Wie DataAccessObject in JavaScript vereinfacht auch die Obj ective-C-Kiasse SO Li te
DataAccess den Abruf oder die Eingabe von Daten in SQLite-Datenbanken, die Sie mit
Ihrer Anwendung ausliefern. Diese Klasse folgt demselben Aufbau w ie DataAccess
Object in JavaScript, sodass Sie den Umgang damit leichter lernen können, auch wenn
Sie mit Obj ective-C nicht vert raut sind.
184
DataAccessObject in nativen Datenbanken verwenden
Da alle Ergebnisse von Abfragen einer WebKit- oder einer nativen Datenbank Objekte mit
JavaScript-Standardtypen sind, müssen Sie die inneren Mechanismen von SQLite-, Web
Kit- und nativen Datenbanken nicht kennen.
Sowohl DataAccessObject als auch die Klasse SO L iteDataAccess bieten die Trans
aktionssicherheit, die nötig ist, damit asynchrone Aufrufe keine Anforderungen unterbre
chen. Sie können gefahrlos eine Reihe von gleichzeitigen Datenbankaufrufen ausführen,
ohne befürchten zu müssen, dass Sie dadurch die Daten in der Datenbank beschädigen.
Im nächsten Kapitel sehen wir uns an, wie Sie einen Wrapper für AJAX-Aufrufe erstellen,
derwie DataAccessObject aussieht und sich auch so verhält.
185
Datenzugriff über das Netzwerk
Manchmal muss eine Anwendung auch auf Daten in einer nicht lokalen Datenbank oder
von einem Webdienst zugreifen. Es kann sogar sein, dass die Dat en auf dem iPhone mit
Dat en synchronisiert werden müssen, die irgendwo im Netzwerk gespeichert sind.
Web-Apps für das iPhone machen dies einfach. Aufgrund ihrer hybriden Nat ur haben Sie
Vollzugriff auf das XM LHt t pRequest-Objekt in JavaScript . ln diesem Kapit el lernen Sie,
wie Sie Dat en von einem RSS-Feed abrufen und in Ihrer Anwendung anzeigen.
Wie beim Datenbankzugriff in Kapitel 6 wi rd im erst en Abschnitt ein einfach zu verwen
dender Wrapper fü r das XM LHt t pReque s t -Objekt vorgestel lt . ln den nachfolgenden Ab
schnitten w ird erklärt, w ie Sie diesen Wrapper erstel len und wie er f unkt ioniert.
Kapitel7 Datenzugriff über das Netzwerk
7.1 ABSCHNITT 1: DIE BEISPIELANWENDUNG
ßROWSERAJAXACCESS
Die Beispielanwendung na t i veDBAccess in Kapitel 6 hat gezeigt, wie Sie Daten in einer
SQLite-Datenbank auf dem Gerät speichern und aus ihr abrufen. ln diesem Kapitel wird
eine ähnliche Anwendung verwendet, die Daten von Webdiensten und Servern abruft. Den
Ordnerfür die Anwendung browserAJAXAccess finden Sie im Verzeichnis iPhone Examples des Ordners QuickConnectiFamily, den Sie von sourceforge.netlprojects/quickconnect/ herun
tergeladen haben.Abbildung7.1 zeigt die laufende Beispielanwendung.
Alle WordPress-Biogs haben einen RSS-Feed, der die letzten zehn Einträge jedes Blogs
bereitstellt, wie Sie in Abbildung 7-2 sehen. Es sieht zwar nicht so aus, als ob dieser Feed
die vollständigen Blageinträge anzeigt, dies ist aber tatsächlich der Fal l. Die Anwendung
browserAJAXAccess zeigt nur die Überschriften an, kann aber sehr leicht mit dem An
satz und dem Code aus Kapitel6 erweitert werden, um die Überschriften und die Postings
zu speichern.
Zum Glück kümmert sich kein RSS-Feed darum, welcher Art der Client ist. Wenn ein Feed
eine Anforderung fü r Blogpostings erhält, sendet er diese im XML-Form, und zwar unab
hängig davon, wer oder was den Feedangefordert hat. Da U I WebV i ew die WebKit-Engine
ent hält, kann es Anforderungen an Feeds senden und die zurückgegebenen XML-Daten
interpretieren. Als Werkzeug dazu verwenden Sie das XMLHttpRequest -Obj ekt, und als
Verfahrensweise AJAX.
188
~ Abbildung p: Die Anwendung br owser AJAXAcc ess mit 8/og/istings von TetonTech
Die Beispielanwendung BrowserAJAXAccess
I AJAX IST KEIN GRIECHE
Eines der größten literarischen Werke aller Zeiten ist die 1/ias. ln diesem epischen Ge
dicht von Homer geht es um den Krieg zwischen den Griechen (oder Achäern) und den
Einwohnern von Troja.
Einer der größten Helden der Griechen ist Ajax. Wiederholt besiegte er seine Gegner,
und einmal bewahrte er ganz allein die griechische Flotte vor der Zerstörung.
Wie die griechische Flotte ist auch die traditionelle Entwicklung von Webseiten Angriffen ausgesetzt. Sie wird als zu langsam, zu schwierig zu verwenden und zu unflexibel
angesehen. Wieder einmal kommt ein AJAX zur Hilfe, aber diesmal ist es kein Grieche.
AJAX steht für Asynchronaus JavaScript and XML.
Das Prinzip von AJAX ist einfach: Der Benutzer erhält stimmigere lnteraktionsmöglich
keiten, indem die Seiten nicht bei jeder Anforderung neu geladen werden. Stattdessen
werden Daten gesendet oder abgerufen und das Ergebnis dann durch dynamisches
HTML angezeigt. Durch die Verwendung von JavaScript kann dies alles auf einer einzi
gen HTML-Seite geschehen.
AJAX sollte Ihnen daher nicht griechisch vorkommen. Und spanisch schon gar nicht.
Ou!ckConn•etiPhoru;a 1.1.1 now :W::Ji '.;lblo r-:b•u:uy I 3 J? PM Now Oui:k.Conn&et ~~loooo a•tWI~kt.
Ou!skCpt~ntetUnyx Dtl!l I lt New !Wl'lllni::!ID fsb IUHY 4. 3 .:,C PM
t took 1~ than OllpCd.ed, bUt 11 ls here. OuiekO:lfl~e!Linw 1.0 bela 1 u3eS tle 4.5 ve ...
O!.l!ckCOI)OtCIIPI!OO!J I 1 2 OON iWij!Jab!o :lf!ll.vy 17 r r PI.C
h te~n)e l tt " r~ rrcm ll dolrn!'b~r 11$if9 OCiPM~ \1!t9ion 1. 1 2 hA9 bf\o@l"l ( rtl'.fi@d .•
Pll'lm Pta lind Mntn Jllt~IJ •• Ii PI.(
l IOO'U 1111) P:tlill't; (lOW SOK ~I wt:rt l'o:ltld ·fn ·n3n0 'M11'1 Oclek.Cot!f'IOC'l A pon IC ::t !:U • ••
~ Abbildung 7-2: Der RSS-Feed von Teton Tech im Browser Safari
189
Kapitel7 Datenzugriff über das Netzwerk
Durch die Kombination des XM LHttpRequest-Objekts mit einfachem JavaScript zur
Bearbeitung einer Webseite kann Ihre iPhone-Web-App Daten aus dem Netzwerk so ver
wenden wie lokale Daten. So können Sie die Vorteile beider Seiten genießen: Ihre Anwen
dung kann sowohl eigenständig als auch im Netzwerkmodus laufen, und soba ld eine Ver
bindung verfügbar ist, können Sie die Daten synchronisieren, um etwaige Abweichungen
auszugleichen. Im Framewerk Qu ickConnectiPhone finden Sie mit ServerAccessObj ect
einen einfach zu verwendenden AJAX-Wrapper.
7.2 ABSCHNITT 2: 5ERVERÄCCESSÜBJECT VERWENDEN
Mit dem AJAX-Wrapper ServerAcces sObj ect können Sie sehr leicht auf Daten im Netz
werk zugreifen, ohne sich um die Feinheiten der API für das XM LHttpRequest-Objekt
kümmern zu müssen. Die API von ServerAccessObj ec t sieht fast genauso aus wie die
von Da taAcces sObj ect (siehe dazu Kapitel 6).
Auch die API von ServerAccessObj ec t hat einen Konst ruktor und zwei Methoden. Der
Konst ruktor enthä lt den URL des entfernten Servers und richtet die Methoden des Objekts ein. Diese Methoden- getData und setData- rufen dann Daten von dem im Konst ruk
tor definierten entfernten Server ab bzw. senden sie an ihn. Tabelle 7.1 zeigt die API von
ServerAccessObject.
Attribut/Methode Rückgabewert Beschreibung Parameter
ServerAcces - Server - Erstellt beim Aufruf URL-Der URLdes Objec t (URU Access - mit dem Schlüssel- Servers, zu dem eine
Objec t wort new ein Verbindung hergestellt ServerAccess - werden soll
Object
ge tData void Die Methode ruft dataType- Der Typ ( dataType, Informationen von der abzurufenden refresh, pa ra - einem Server im Daten. Dafür gibt me t erSeq uence, Netzwerk ab. Dies es die beiden HTTPHeaders) ist der GET-Typ Mögl ichkeiten
einer Anforderung. ServerAccess -
Diese Methode ist Obj ect . XML und
t hreadsicher. ServerAccess -
Obj ect . TE XT.
190
ServerAccessObject verwenden
{Fortsetzung) refresh- Ein
boaleseher Wert,
der anzeigt, ob
eine erzwungene
Aktualisierung der
Daten vom Server
erfolgen soll.
parameter -
Sequence- Alle
Parameter, die zum
URL hinzugefügt
werden müssen. Das
Fragezeichen am
Anfang dürfen Sie
nicht in diese Folge
aufnehmen.
HTTPHeaders -Ein
assoziatives Array der
Namen und Werte des
Anforderungsheaders,
die zusammen mit der
Anforderung gesendet
werden sollen.
set Da ta Keiner Die Methode da taType- DerTyp ( da taTy pe, pa ra - ändert oder erstellt der zu ändernden
meterSequence, Informat ionen bzw. zu erstellenden data, HTTPHeaders) auf einem Server Daten. Dafür gibt
im Netzwerk oder es die beiden
übergibt sichere Möglichkeiten
Para metertypen. ServerAccess -
Dies ist der POST -Typ Obj ect. XML und
einer Anforderung. ServerAccess -
Diese Methode ist Obj ect. TEXT.
t hreadsicher.
191
Kapitel7 Datenzugriff über das Netzwerk
(Fortsetzung) parameter-
Sequence- Alle
Parameter, die zum
URL hinzugefügt
werden müssen. Das
Fragezeichen am
Anfang dürfen Sie
nicht in diese Folge
aufnehmen.
data -Alle Daten, die
Sie in die Übertragung
aufnehmen möchten.
Dies können umfang-
reiche Mengen von Zeichendaten, Datei-
Uploads usw. sein.
HTTPHeaders- Ein
assoziatives Array der
Namen und Werte des
Anforderu ngsheaders,
die zusammen mit
der Anforderung
gesendet werden
sollen.
Tabelle p: Die API von Se rve rAccessObj ec t
Die Datei ServerAccessObjectjs, die Sie sowohl in der Dashcode- als auch in der Xcode
Vorlage in der Gruppe QCIPHONE finden, ent hält den Wrapper ServerAccessObject.
Diese JavaScript-Datei w ird von beiden Vorlagen automatisch zur Datei index.htmllhrer Anwendung hinzugefügt.
Die Funktion getSiteData BC F aus der Datei functionjs verwendet diese JavaScript
Kiasse. Diese Datei enthä lt al le Steuerfunktionen für die Beispielanwendung browse r
AJAXAccess. Weitere Informationen über diese Funktionen und darüber, w ie Sie sie erstel len können, finden Sie in Kapitel 2, »Die Modularität von JavaScript f ür iPhone
Anwendungen«.
Der Zweck der Funktion getSi teDataBCF besteht darin, Einträge aus dem Blog des Autors
abzurufen. Solche Abrufvorgänge können leicht mit ServerAccessObject erled igt
werden, w ie die Zeilen 2 bis 5 des folgenden Codes zeigen.
192
ServerAccessObject verwenden
1 function get SiteDataBCF(paramet ers)( 2 var site = new ServerAccessObject( 3 ' http : llteton tech. wordpress.comlfeedl'); 4 site .getData(ServerAccessObject.XML, 5 ServerAccessObject.REFRESH); 6 II Da di eser AJAX- Datenzugriff saufruf asynchron ist, 7 II soll te diese BCF nichts zurückgeben. 8 9
Die Zei len 2 und 3 zeigen die Konstruktion eines neuen ServerAccessObject. lhm wird
der URL des zu verarbeitenden RSS-Feeds übergeben, in diesem Fal l der URL zum Blog des
Autors unter http://Tetontech.wordpress.com!feed. Um auf einen anderen Blog zuzugrei
fen, ersetzen Sie entsprechend den UR L.
ln Zeile 4 und 5 wird dann das neue Objektnamens s i te verwendet, um die Daten zu gewinnen. Da es sich um einen RSS-Feed handelt und da bekannt ist, dass der Server Daten
im XML-Typ an die Anwendung zurücksendet, wi rd der Datentyp auf XML gesetzt. Der
zweite Parameter ist ein Flag, das eine Akt ualisierung der Daten statt der Verwendung ei
ner zwischengespeicherten Version erzwingt. Dies ist erforderlich, wenn Sie sicherstel len
möchten, dass die empfangenen Daten sämtliche auf dem Server gespeicherten Ände
rungen ent halten.
Es kann jedoch schlechte Folgen haben, in jedem Fal l blind eine Aktualisierung zu erzwin
gen. Wenn Siedies t un, obwoh I gar keine Aktua I isieru ng erforderlich ist, kann dies bei weiter
Verbreitung Ihrer Anwendung zu einer Überlastung von Server und Netzwerk führen. Aus
diesem Grund sol lten Sie abwägen, ob wirklich die absolut neuesten Daten erforderlich sind
oder ob Sie mit leicht veralteten Daten leben können.
Wie bei DataAccessObject sind auch alle Aufrufe von ServerAccessObj ect asyn
chron. Es können gleichzeitig mehrere Aufrufe ausgeführt werden, sofern für jeden ein
neues ServerAccessObject erstel lt w ird. Wenn Sie das Framework QuickConnectiPhone verwenden, müssen Sie nicht wie in AJAX eine Cal lback-Funktion defin ieren. Das
Framework sorgt dafür, dass alle verbleibenden BDFs (Business Control Functions) und
VCFs (View Cont rol Functions) ausgeführt werden, die demselben Befehl zugeordnet wer
den wie die BDF, die das Se rve r Acces sübj ect aufgerufen hat.
Die Funktionen getSi teDataBCF und di sp l aySi teDataVC F sind beidein der Datei
mappingsjs dem Befehl samp l eQuery zugeordnet, wie Sie in Kapitel 2 erfahren haben.
Das bedeutet, das Framework sorgt dafür, dass die von getSi teDataBCF angeforderten
Daten garantiert an d i spl aySi teDataVCF übergeben werden.
193
Kapitel7 Datenzugriff über das Netzwerk
Den Code von d i s p l ayS i teDa ta VC F finden Sie im folgenden Listing. Der an diese Funk
tion übergebene Parameter resu l ts ist ein Array aus JavaScript-Objekten für die ein
zelnen BCFs, die dem Befehl sampl eQuery zugeordnet sind. Die Methode getData von
ServerAcces sObj ect erstellt ebensowie die gleichnamige Methodevon Da taAccess
Object ein QueryResul t -Objekt (weitere Informationen über QueryResul t-Objekte
finden Sie in Kapitel 6).
Nachdem im folgenden Code die durch die Variable container dargestellten Elemente
gelöscht sind, wird in Zeile 9 das QueryResul t-Objekt mit den Ergebnissen des AJAX
Aufrufs abgerufen. Da es sich bei getSiteDataBCF um die erste BCF handelt, die dem
Befehl samp l eQue ry zugeordnet ist, wird das durch diesen Aufruf hervorgerufene Ergeb
nis zum ersten Objekt im Arrayparameter resul ts.
Wie in Kapitel 6 gezeigt, haben QueryResu l t-Objekte ein Attribut namens data. Bei
XML-Anforderungen wie der in getSiteDataBCF wird dieses Attribut mit dem resultie
renden XML-Dokument gefü llt.
Da dieses Dokument sehr stark dem HTML-Dokument ähnelt, das gewöhnlich für dynami
sches HTML zum Einsatz kommt, wird es auch sehr ähn lich behandelt. Dieselben Arten von
Methoden stehen zur Verfügung, z.B. getEl emetßyld und getEl ementsßyTagName. Das Dokument besteht auch aus Node-Objekten mit Eitern-, Kind- und Geschwisterbezie
hungen. Zur Interpretation dieser Daten können Sie alle Standardmethoden und -ansätze
verwenden.
Den Aufruf der Helferfunktion pa rseWordPress Feed in der Datei RSSUtilitiesjs sehen
Sie ebenfal ls in Zeile 9· Er verwendet diese Standardmethoden, um ein zweidimensionales
Array aus Blageinträgen namens entri es abzurufen. Jeder Eintrag im Array besteht aus
dem Datum des Postings, dem Inhalt und dem Titel.
1 function displ aySiteDataVCF(results, parameters){ 2 var container = 3 document.getEl ementßyld( ' queryResul ts ' ) ; 4 II Löscht die Inhal te des Containers 5 whi l e(container. l astChi l d) { 6 container.removeChi l d(container.lastCh i l d); 7 } 8 II Estell t Eintragsobjekte mit einem WordPress-Parser 9 var entries = parseWord PressFeed (results[O ] .data);
10 var numEntries = entries. l ength;
194
ServerAccessObject verwenden
11 // Fügt f ür jeden Eintrag Titel und Datum 12 // i n den div - Conta i ner ein 13 for ( var i = numEntries - 1; i >= 0; i - ){ 14 var entry = entries[i ] ; 15 var publishDate = entry .date; 16 var t i tle = entry.tit l e; 17 18 var t i tleElement = document . createElemen t ( 'h2' ) ; 19 t itl eE l ement.innerText = entry.title; 20 container.appendChild(titleEl ement); 21 22 var da teE l ement = document.createElement( 'h3 ' ); 23 dateEl ement . i nnerText = entry .date ; 24 contai ner.appendChi l d( dateEl ement); 25 26 var hardRu l e = document. createEl ement( ' hr' ) ; 27 container . appendChi l d( hardRul e); 28 29
Beim Zugriff auf die einzelnen von der Helferfunktion pa rseWordPress Feederstellten
Einträge werden in den Zei len 13 bis 18 Objekte für HTML-Eiemente erstellt und in den
Container eingefügt, sodass die Anzeige den Titel und das Datum der Blageinträge um
fasst. Um die Einträge voneinander zu trennen, wird eine Lin ie eingefügt.
Dieses Beispiel zeigt, w ie Sie mit RSS-Feeds umgehen, aber die anderen Arten des Zugriffs
lassen sich mindestens ebenso einfach handhaben. Sie können auch eine Anforderung
vom Typ TE XT machen und HTML-Code abrufen, der in die Benutzerschnittstelle Ihrer An
wendung eingefügt wird. Al lerdings w ird aus Sicherheitsgründen davon abgeraten. Statt
dessen können Sie bei einem Aufrufvom Typ TEXT JSON-Code abrufen.
Welche Art von Daten Sie auch abrufen müssen, mit ServerAccessObject geht es
einfach. lnstanzi ieren Sie das Objekt, und rufen Sie getData für eine GET-Anforderung
bzw. set Data für eine POST-Anforderung auf ln beiden Fä llen übergibt das Framework
QuickConnectiPhone die Informationen an alle nachfolgenden Steuerobj ekte, die Sie dem
Befehl zugeordnet haben.
195
Kapitel 7 Datenzugriff über das Netzwerk
JSON IST AUCH KEIN GRIECHE
JSON wird wie der englische Name Jason ausgesprochen, der auf den griechischen
Helden Jason aus der Argonautensage zurückgeht. Bemerkenswert ist, dass Jason und
seine Gefährten vor allem wegen ihrer langen Reise zur Rückgewinnung des Goldenen
Vlieses bekannt sind.
Auch bei JSON geht es um eine lange Reise, nämlich darum, wie JavaScript-Objekte große
Entfernungen im Netzwerk überbrücken. Das Akronym steht fü r JavaScript Object Nota
tion, aber das ist nur ein neumodischer Name für etwas, das es schon lange gibt.
Der folgende Code zeigt, wie Sie ein JavaScript-Objekt erstellen und darin einen Vor
und einen Nachnamen speichern:
var anObj ect = new Obj ect ( ) ; anObj ect . fName = 'bob '; anObj ect . l Name = ' jones ';
Im folgenden Code sehen Sie dies in der Objektnotation:
var anObj ect = { fN ame : 'bob '. l Name : ' jones ' ) ;
Was ist nun richtig? Beide Ansätze führen zum gleichen Ziel. Die zweite Vorgehens
weise ist höchstwahrscheinlich schneller, aber bei umfangreichen Objekten bietet die
erste Möglichkeit eine bessere Lesbarkeit und Wartungsfreundlichkeit.
Die Objektnotation hat den Vorteil, dass Sie wie folgt überall als Zeichenstring gesen
det werden kann:
"{fName :'bob ', l Name:'jones ' J"
Dieser String kann dann der JavaScript-Standardfunktion ev a l übergeben werden,
um ihn in ein Objekt umzuwandeln, aber das ist gefährlich. Eine sicherere und einfach anzuwendende Vorgehensweise finden Sie in Anhang A, »Einführung in JSON«.
Ist es ein Zufall, dass mit AJAX und JSON zwei griechische Helden zur Rettung der
Webentwicklung herbeieilen? l Urteilen Sie selbst!
7.3 ABSCHNITT 3: 5ERVERÄCCESSÜBJECT
/
Im vorherigen Abschnitt haben Sie gesehen, w ie Sie ServerAccessObj ec t einset zen,
damit Sie sich nicht um AJAX und die API von XM LHt t pReques t kümmern müssen. in diesem Abschn itt lernen Sie, worum es sich dabei handelt und wie Sie diese Technik und die
ses Obj ekt einset zen. Wenn Sie einfach nur Se r ve r Acces sObj ect verwenden, aber nicht
genau wissen möchten, wie es f unktioniert, können Sie diesen Abschnitt überspringen.
196
ServerAccessObject
Der Zweck von Serve r AccessObjec t in QciPhone/ServerAccessObjectjs besteht darin,
dem Programmierer oder Entwickler so wenige Kenntnisse über AJAX aufbürden zu müssen
wie möglich. Daher ist diese Klasse so aufgebaut, dass ihre Methoden und Konstruktaren
denen des JavaScript-Datenbankwrappers DataAcces sObj ect aus Kapitel 6 stark ähneln.
Dank der vereinfachten API können Programmierer, die mit AJAX nicht vertraut sind, Daten
aus dem Netzwerk abrufen, ohne erst viellernen zu müssen. Wenn Sie die API für eines die
ser Zugriffsobjekte kennen, w issen Sie auch, wie Sie die anderen benutzen müssen.
Der Konstruktor von ServerAcces sObj ect ist die einfachste der darin enthaltenen Me
thoden. Er speichert den URL des entfernten Servers und definiert dann die Methoden
des Objekts. Die einzige funktionale Zei le des Konstruktors, die Sie im Folgenden sehen,
speichert den URL für die spätere Verwendung im URL-Attribut des Objekts:
t his . URL = URL ;
Auf dieses URL-Attribut greift der Programmierer niemals direkt zu. Stattdessen wird die
private Methode ma keCa l l verwendet.
Diese Methode ist Herz und Seele eines Se rve rAcces Obj ect. Sie verrichtet die gesamte
Arbeit, wenn das Objekt aufgefordert ist, irgendeine Form von Serverzugriff durchzuführen. Als Fassade dienen ihr die beiden Methoden getDa ta und set Da ta . Die API-Beschrei
bung in Tabelle 7.2 erläutert deren grundlegende Verwendung.
Wie Sie im folgenden Abschnitt sehen, wird für diese Fassaden eine der vielen Standard
vorgehensweisen zur Zuweisung von Methoden zu Objekten verwendet. Dabei wird durch
den Aufruf des Konstruktars funct ionein Funktionsobjekt erstellt und das Ergebnis einem
Attribut des zurzeit durch das Schlüsselwort key repräsentierten Objekts zugewiesen.
Die beiden Fassadenmethoden getData und setData sind fast identisch. Seide nehmen
vier Parameter entgegen und übergeben diese und drei weitere an die zugrunde liegende
Methode ma keCa ll . Die zusätzlichen Parameter entsprechen dem ersten, fünften und
siebenten im Aufruf von getData und dem ersten, dritten und siebenten in dem von
setData. Den fünften Parameter der Methode ma keCa l l bilden die Daten, die im Rah
men der POST -Anforderung an den Server übertragen werden. Dies ist bei der Methode
getData natürlich nicht erforderlich, weshalb hier nul l übergeben wird.
t his .getData = function ( dataType, refresh, parameterSequence, HTTPHeaders){
var passThroughParameters =
generatePassThroughParameters ( ); this.ma keCa ll ( ' GET ' . dataType, refresh,
parameterSequence, nul l . HTTPHeaders. passThroughParameters);
197
Kapitel7 Datenzugriff über das Netzwerk
this.setData = function(dataType, parameterSequence, data, HTTPHeaders ){
var passThroughParameters =
generatePassThroughParameters(); this.makeCall('POST', dataType, true,
parameterSequence, data, HTTPHeaders, passThroughParameters);
Der Funktionsaufrufgenera tePassTh roughPa ramete rs sammelt alle Informationen, die
erforderlich sind, damit das Framewerk mit der Verarbeitung der BCFs und VCFs fortfahren
kann, die der BCF zugeordnet sind, von der das ServerAccessObject verwendet wird.
Attribut/
Methode
makeCal l (cal lType,
dataType,
re f res h ,
parameter -
Sequence,
data, HTTP -
Headers ,pass -
ThroughPara -
meters)
Rückgabe
wert
void
Beschreibung
Eine Methode,
die als privat bet rachtet wer-
den sollte. Diese
Methode erledigt
die eigentlichen
AJAX-Aufrufe an
den Server und
kümmert sich
um die Ergeb-
nisse.
Tabelle 7-2: API der privaten Methode ma keCa 11
198
Parameter
callType-EntwederGET oder POST
dataType-EntwederTEXT oder XML
refresh- Ein boolesches Flag, das
anzeigt, ob eine Aktualisierung der
Daten erzwungen werden soll.
pa rameterSequence- EinString der URL-Parameter, die in der
Anforderung verwendet werden
da t a -Zeichen- oder Bi nä rdaten,
die zusammen mit POST-
Anforderungen gesendet werden
HTTPHeaders- Ein assoziatives
Array der Namen und Werte des
HTIP-Anforderungsheaders
passThroughParameters-
Ein Array von Werten, die das
Framewerk benötigt, um nach dem
Empfang der Daten vom Server mit
der Verarbeitung fortzufahren
ServerAccessObject
Der dritte Parameter der Methode ma keCa l l ist ein boolesches Flag, das anzeigt, ob der
Cl ient, in diesem Fall die U I We bVi ew, Caching einsetzen soll oder nicht. Bei der Methode
setDa ta ist Caching offensichtl ich nicht sinnvoll, weshalb hier t r ue hart kodiert ist, um
die Zwischenspeicherung auszuschalten.
Wenn Sie diese Parameter in die Methodensignatur von ma keCa l l aufnehmen, kann die
Methode das Verha lten zum Abrufen von Daten von einem entfernten Server sowie zum
Senden effektiv kapseln. Dieses Entwurfsmuster der Fassaden-Helferfunktionen wird häu
fig verwendet, wenn, wie in diesem Fall, ein Großteil, aber nicht der gesamte Code zwei er oder mehrerer Methoden bzw. Funktionen identisch ist und ohne die Fassaden eine erheb
liche Verdopplung von Code auftreten würde.
Um die Methode ma keCa l l verstehen zu können, müssen Sie die API des zugrunde lie
genden JavaScript-Objekts XM LHt t pReq ues t kennen. Diese API ist in U I We bVi ew imple
mentiert und wird in Web-Apps und in Mobile Safari verwendet.
Das einzige Objekt in dieser API ist XMLHt t pReques t (siehe Tabelle 7-3).
Attribut/
Methode
XM LHttpRequest ()
abort( )
getAl l Res ponse -
Headers ()
get ResponseHeader
CaHeaderName )
Rückgabe
wert
XMLHttp -
Request
vo id
String
String
Beschreibung Parameter I
Ein Konstruktor für das Keine
Objekt
Beendet die Anforderung, Keine
zu der diese Methode
gehört
Als Ergebnis dieses Aufrufs Keine
wird einString mit allen
Namen und Werten
des Antwortheaders
zurückgegeben.
Gibt einen String mit aHeaderName-
dem Wert des Headers Der Name des HTIP-
mit dem angegebenen Antwortheaders,
Namen zurück. Falls kein dessen Wert
solcher Header existiert, abgerufen
wird nu l l oder gar nichts werden soll
zurückgegeben.
199
Kapitel7 Datenzugriff über das Netzwerk
open(type, void Öffnet eine Verbindung type- EinString
UR L , asynch, zum gewünschten Server mit dem Wert GET userName, und bereitet sie vor. oderPOST passWord)
asynch- Ein
boolesches Flag,
das anzeigt, ob
die Anforderung
asynchron erfolgen
soll. An dieser Stelle
muss stets true
übergeben werden.
userName- Ein
opt ionaler Para-
meter. Dies ist der
Benutzername,
derfür den Zugriff
auf die im URL
angegebene Datei
oder das Verzeichnis
erforderlich ist.
passWord-Ein
optionaler Pa rameter.
Dies ist das Kennwort
f ürden angegebenen
Benutzernamen,
dasfür den Zugriff
auf die im URL
angegebene Datei
oder das Verzeichnis
erforderlich ist.
200
ServerAccessObject
send(data) void Eine Methode zum data- Die an
Anhängen von Zeichen- die Anforderung
und Binärdaten an eine angehängten
Anforderung. Sie wird Informationen
bei POST-Anforderungen
wie dem Hochladen von
Dateien verwendet.
SetRequest - void Eine Methode, die name-Ein String, Header ( name, Standardheaderwerte der den Header value ) überschreiben oder bezeichnet
benutzerdefinierte v a l ue- Ein String,
Headernamen und der den mit dem
-werte zu einer Namen verknüpften
Anforderung hinzu-Wert angibt
fügen kann.
onreadystate - Ein Attribut, das auf change eine Funktion gesetzt
w ird. Die angegebene
Funktion wird aufgerufen,
wenn das Ereignis
on r eadystatechange
ausgelöst wird. Dies
geschieht bei jedem
Wechsel von readyState.
readyState Eine Folge von
lntegerwerten, die den
Status der Anforderung
angeben. Folgende Werte
sind möglich:
o- Die Sendemethode
w urde noch nicht
aufgerufen.
201
Kapitel7 Datenzugriff über das Netzwerk
(Fortsetzung) 1- Die Anforderung wird an
den Server gesendet.
2- Der Server hat die
Anforderung empfangen.
3- Ein Teil der Antwort vom
Server wurde empfangen.
4- Die gesamte Antwort
vom Server wurde
empfangen.
responseText Die in Textform vom
Server gesendeten Daten
a bzüglich der HTIP-
Antwortheader
response XML Die in XML-DOM-Form vom
Server gesendeten Daten.
Sind die XML-Daten nicht
gü ltig, ist der Wert nul l .
status Eine vom Server gesendete
Zahl, die den Erfolg
oder Feh lsch lag einer
Anforderung angibt. Am
häufigsten sind die beiden
folgenden Werte:
404- Nicht gef unden
200- Erfolg
Eine vollständige Liste
fi nden Sie unter http:! I www.w3.org/Protocols! rjc2676!rfc2676-seC1o.html.
statusText Ein vom Server erstellter
String mit einer den Status-
codebegleitenden Meldung.
Tabelle 7-3: API des XM LHttpReques t -Objekts
202
ServerAccessObject
Die am häufigsten verwendeten Methoden dieser API sind der Konstruktor sowie open
und send. Im folgenden Code finden Sie ein einfaches Beispiel zur Verwendung dieser
Methoden und anderer häufig genutzter Attribute. Hier wi rd die Hauptseite des Open
Source-Projekts WebKit in Textform abgerufen.
Beachten Sie vor allem zwei Punkte in diesem einfachen Beispiel. Erstens weist das reques t
Objekt einen globalen Gültigkeitsbereich auf. Es steht zur Verwendung in der Funktion
handleResponse zur Verfügung, die automatisch von der Browser-Engine aufgerufen wird,
wenn sich der Statuswert readyState ändert. Dadurch w ird der Code vereinfacht, aber es
besteht ein Problem, wenn zwei Anforderungen einander versehentlich überschneiden oder
zur gleichen Zeit gesendet werden müssen.
var request = new XMLH t t pRequest(); request.onreadystatechange = handl eRes ponse ; request.open( IGET I . l http: llwebkit.orgl l . true); request.sent( I I ) :
function handleRes ponse(){ if(request.readyState == 4 ){
i f ( request.status == 200){ var resul t = response.responseText; II Hier wird das Ergebni s auf irgendeine Weise verarbeitet.
Aufgrund des globalen Gültigkeitsbereichs derVariablen reques t ist dieses einfache Bei
spiel nicht th readsicher. Da die Anforderungen asynchron erfolgen, ist es möglich und oft
auch wahrscheinlich, dass sie einander überschneiden. Um dieses Problem zu lösen, ist
diese globale Variable in Se rve rAcces sObj ect gekapselt.
Das zweite Problem besteht darin, dass die Anforderung an einen vollständigen URL
gesendet wird. ln Standardbrowsern kann ein XM LHttpRequest-Objekt nur Daten von
dem Server abrufen, dem es entsprang. Für eine U I WebVi ew in einer Web-App gi lt diese
Einschränkung j edoch nicht . Sie kann Daten von jedem Server abrufen, da sie kein Server
ist. Dies ist Segen und Fluch zugleich.
ln Browsern besteht diese Einschränkung, um Angriffe durch siteübergreifendes Scripting
(Cross-Site Scripting, XSS) zu unterbinden. Solche Angriffe t reten auf, wenn schädlicher
JavaScript -Code in ansonsten harmlosen HTML-Code eingefügt wi rd, den Ihre Anwen
dung anfordert. Da eine U IWebVi ew kein Browser ist, sind Sie nicht dafür zuständig, die
Anwendung gegen solche Angriffe zu schützen. Zum Glück versorgt Sie das Framework
QuickConnectiPhone mit der Mögl ichkeit, Sicherheitssteuerf unktionen (Security Control
203
Kapitel7 Datenzugriff über das Netzwerk
Functions, SCF) zuzuordnen, die das ServerAcces sObj ec t aufruft, bevor es die Ergeb
nisse der Anforderung an die VCFs übergibt.
Diese SCFs werden wie VCFs erstellt und mithilfe der Funktion mapCommandToSCF zuge
ordnet. Beispiele dafür finden Sie in Abschnitt 4·
Die API des XMLHttpRequest-Objekts enthält keine Möglichkeit, um eine Aktualisierung
zu erzwingen. Darum kümmert sich das ServerAccessObj ect, indem es einen der stan
dardmäßigen HTIP-Anforderungsheader einrichtet.
if(refresh) { /* * Wenn wir das Cachi ng deaktivieren und ei nen Aufru f beim * Server erzwingen *möchten , muss der Header ' I f -Modified - Si nce ' au f einen Wert * i n der * Vergangenheit einges t el l t werden .
*I http. setRequestHeader ( " I f - Modif i ed - Si nce ",
" Sat, 1 Jan 2000 00 : 00:00 GMT" ) ;
Der Header If -Mod if i ed - Si n ce weist den Server an, Daten zu senden, fal ls das a nge
forderte Element ein Änderungsdatum aufweist, das hinter dem Datum im Headerwert
liegt. Wenn Sie den Wert auf ein Datum in der Vergangenheit setzen, stellen Sie sicher,
dass keine zwischengespeicherten Daten verwendet werden.
Die API von ServerAccessObject hat j edoch kein Flag, mit dem der Benutzer die An
forderung als synchron oder asynchron defin ieren kann. Al lgemein wird anerkannt, dass
AJAX-Aufrufe asynchron erfolgen sollten, da die Web-Engine dadurch fü r weitere Einga
ben des Benutzers verfügbar bleibt. Wären sie synchron, würde sich die U I WebVi ew beim
Drehen des iPhones in einen leeren, weißen Bi ldschirm verwandeln. Dies würde auch ge
schehen, wenn der Benutzer durch die Ansicht blättert, während eine Anforderung an den
Server unterwegs ist. Beides ist fü r den Benutzer unschön. Da das XMLHttp Request also
besser nicht synchron verwendet werden soll, sind in ServerAccessObject alle Anfor
derungen als asynchron hart kodiert.
Anders als in den früheren Beispielen verwendet das ServerAccessObject keine ei
genständige Funktion, um on readys tatechange-Ereignisse zu verarbeiten, sondern
eine anonyme Funktion (weitere Informationen über anonyme Funktionen erhalten Sie in
Kapitel 3, »Benutzerschnittstellen für das iPhone erstellen«). Der Grund dafür liegt darin,
dass anonyme Funktionen den Gültigkeitsbereich der übergeordneten Funkt ion haben.
204
ServerAccessObject
ln diesem Fall sind daher alle in der Methode ma keCa l l deklarierten lokalen Variablen auch in der anonymen onreadystatechange-Funktion verfügbar. Damit ist das zuvor beschriebene Problem der globalen Variablen gelöst. Die Variable http wird als das neu erstellte XMLHttpRequest-Objekt deklariert, das in makeCa l l verwendet werden soll. Dadurch verbleibt sie auch dann im Gültigkeitsbereich, wenn die anonyme Funktion für onreadys tatechange aufgerufen wird.
Wenn Ihnen das Prinzip anonymer Funktionen nicht vertraut ist, widerspricht dieses Vorgehen der Intuition, und wenn Sie anonyme Funktionen schon kennen, mag es hier so scheinen, als ob Sie mit einerVorgehensweise durchkommen, von der normalerweise abgeraten wird. Der folgende Code enthält die gesamte anonyme Funktion.
1 http.onreadystatechange = fun ction (){ 2 3 i f (http.readySta te == ServerAccessObject.COMP LET E
I I http.aborted ){ 4 II Der Standardplatzha l ter für al le Arten von Datenabfragen 5 var queryResult = new QueryResult(); 6 II Dies sind benutzerdefinierte Feh l erheader, 7 II die Sie bei Bedarf vom Servercode senden können.
8 if (! http.aborted ){ 9 queryResult.errorNumber
10 http.getResponseHeader( ' QC -Error -Number ' ); 11 queryResult.errorMessage = 12 http.getResponseHeader( ' QC -Error -Message ' ) ; 13 14 15 16 17
if Chttp.aborted ){ queryResult.errorNumber
queryResul t.errorMessage -100 "Request timed out. " ;
18 el se if(http.status != ServerAccessObject . HTTP_O K 19 && http.status != ServerAccessObject.HTTP_LOCAL 20 && http.status != 21 ServerAccessObject.OSX_HTTP_File_Access){ 22 23 24 25 26
queryResul t.errorNumber = http.status; queryResul t.errorMessage = "Bad access type.";
205
Kapitel7
27 28
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 } ;
206
Datenzugriff über das Netzwerk
I* * Ruft di e Daten ab, falls der Server die Me l dung zurückgibt, * dass di e An f orderung erfol gre i ch verarbeitet wurde, * oder wenn di e An f orderung direk t an eine Datei auf de r * Serverf estpl atte ging . * Abruf erfol gt al s Text oder XM L *I
i f(queryResu l t . errorNumber ==null)( queryResul t .da t a = ht t p[ ' response ' +dataType]; if(!dispatchToSCF(passThroug hPa rameters[O J .
queryResul t .data)){ queryResult . er rorNumber =
ServerAccessObject .I NSECURE_DATA_R ECE IVED: queryResult . errorMessage =
"Insecure data rec i eved . " ;
I* * Ruft die näc hste St euerfunkt ion in der Liste *auf , um resu l t Data zu übergeben *I i f(wi ndow . ca l l Func)( I* * Kann von außerhal b einer * dispatchToBCF - Fun kt ion aufgerufen werden . *Wenn ja , dann muss kei ne cal l Func -* Funkt ion def i niert sei n. *I
var t heResul t s = new Array(); t heResul t s . pus h(queryResu l t) ; t heResul t s . pus h(passThroughParameters) ; requestHand l er(passThroug hParameters [OJ. passThroughParamet ers[2 ], theRes ul ts) ;
ServerAccessObject
Die Zeilen 36 bis 42 im vorstehenden Codefragment enthalten die bereits erwähnten SCF
und VCF-Aufrufe. Zeile 36 sieht wie der Code im Frontcontroller von Kapitel 2 aus. Tatsächlich ist sie fast identisch mit dem dort beschriebenen Aufruf der Funktion chec kVal i da
t i on und verhält sich auch so.
Benutzer können schädliche Daten eingeben, aber auch Server können solche Daten sen
den. Die Funktion checkSecur i t y ist eine Funktion in der Art eines Anwendungscont
rollers wie c hec kVa l i da t i on. Sie ruft die SCFs auf, die Sie in der Datei mappingsjs dem
selben Befehl zugeordnet haben wie der BCF, die das ServerAccessObj ec t verwendet.
Damit können Sie beliebig viele Sicherheitsprüfungen auf die empfangenen Daten an
wenden, um sich gegen Angriffe durch siteübergreifendes Scripting zu schützen.
Nach der Überprüfungwerden die Daten einem QueryResul ts-Obj ekt hinzufügt, damit
die Anwendung mit ihrerVerarbeitungfortfahren kann. Dies geschieht durch einen Aufruf
der Funktion r equestHandl er. Die passThroug hPa r amete r s werden hier verwendet,
da sie die als nächste aufzurufende Steuerfunktion sowie den Befehl entha lten, der den
Aufruf der BCF ausgelöst hat. Durch den Aufruf von r equestHand l er stellt die Metho
de ma keCa l l von ServerAccessOb ject sicher, dass alle Ihre Steuerfunkt ionen in der
Reihenfolge aufgerufen werden, in der Sie sie in der Datei mappingsjs zugeordnet haben.
Da auch das Ergebnisobjekt the Resu l ts übergeben wird, steht es allen nachfolgenden
Steuerfunktionen zur Verfügung. Das bedeutet, dass Sie die Daten anschließend in j eder
passenden Weise verwenden können.
~ Abbildung 7-3: Sowohl Benutzer als auch Server können einer Anwendung schädliche Daten liefern. Das Prinzip der doppelten Frontcontroller schützt Ihren Anwendungscode vor fehlerhaften und möglicherweise schädlichen Daten.
207
Kapitel7 Datenzugriff über das Netzwerk
Da die anonyme onreadystatechange-Funktion diese beiden anwendungscontroller
ähnlichen Funktionsaufrufe enthält und die einzige Funktion ist, an die der Server Daten
sendet, f ungiert sie als zusätzlicher Frontcontroller Ihrer Anwendung. Wenn Sie das Se r
ver Acces sObj ect also für den gesamten Datenzugriff über das Netzwerk verwenden,
erhalten Sie dadurch die Vorteile, die in Kapitel 2 fü r Standardanwendungen aufgezeigt
wurden, für die gesamte Kommunikation über das Netzwerk.
Das Muster der doppelten Frontcontroller sorgt für die nötige Sicherheit der Anwendung
und gibt Ihnen gleichzeitig die erforderliche Flexibilität für den Datenabruf von beliebi
gen Servern. Abbi ldung 7·3 zeigt, wie die beiden Frontcontroller Ihre Anwendung und Ihre
Daten schützen.
7.4 ABSCHNITT 4: SICHERHEITSFUNKTIONEN
Das ServerAccessObj ect ruft SCFs auf, um die Gültigkeit und Sicherheit der vom Ser
ver abgerufenen Daten zu prüfen. Sie entsprechen damit den in Kapitel 2 behandelten
Validierungsfunktionen und folgen dem Muster aller übrigen Steuerfunktionen.
Damit eine SCF aufgerufen werden kann, muss sie einem Befehl zugeordnet sein. Wenn
Ihre Anwendung z.B. verlangt, dass sich ein Benutzer anmeldet, damit ihm JSON-Daten
gesendet werden können. Eine solche Zuordnung kann wie folgt aussehen:
mapCommandToSCF( ' l ogin ' . chec kForFunctions);
Das bedeutet, dass Sie auch die Funkt ion checkForFunct i ons benötigen, die von
checkSecur i ty aufgerufen werden kann.
Da die Bibliothek j son2 in der Datei QciPhoneljson2js zur Verf ügung steht, können Sie
diese Funktion sehr leicht schreiben.
Funct ion checkForFunctions(data){ i f( data == JSON . stringify(JSON.parse(data){
return true;
return fa l se;
Bei der Analyse der Daten fügt die Methode J SON. parse zusätzliche Zeichen in den String
ein, fa lls sie auf Funktionsdeklarationen oder Funkt ionsauf rufe stößt. Dadurch schlagen diese Versuche zur Defin it ion oder zum Aufruf von Funktionen feh l, was einen dringend
benötigten Schutz gegen XSS-Angriffe (siteübergreifendes Scripting) bietet.
208
Zusammenfassung
Dies können Sie f ür Ihre Überprüfungen nutzen, indem Sie das neu erstellte JavaScript
Objekt wieder in einen String zurückverwandeln und ihn mit dem Origina l vergleichen.
Treten Abweichungen auf, weiß die Anwendung, dass die vom Server empfangenen Daten
schäd lichen Code enthalten.
Das bedeutet, dass der an Sie gesendete JSON-Text keine Funktionsdefinitionen und -auf
rufe entha lten darf Das ist eine gute Sache, denn ansonsten könnten Sie niemals sicher
sein, ob die JavaScript-Funktionen im JSON-Text Ihr Code oder Schadcode sind, der im Rah
men eines XSS-Angriffs eingeschmuggelt wurde.
7.5 ZUSAMMENFASSUNG
Mit ServerAccessObj ect haben Sie eine einfache, sichere Möglichkeit, um Daten aus
Quellen im Netzwerk in Ihren Web-Apps abzurufen. Sie können eine einfach zu nutzende
API verwenden, die ebenso wie die Da taAccess -API den Lernaufwand stark verringert.
Durch SCFs können Sie den abgerufenen Code so sorgfältig prüfen, wie Sie es für erforder
lich halten.
Ein ServerAccessObject kann Daten aus dem Netzwerk abrufen und mithi lfe eines
Da taAcces sObj ec t für die weitere Verarbeitung speichern oder direkt verwenden, wie
es in der Beispielanwendung browse r AJAX Exampl e geschieht. Damit ist es auch mög
lich, loka le Daten auf dem Gerät mit denen auf einem entfernten Rechner zu synchroni
sieren.
Mit ServerAccessObject können Sie Code erstel len, der automatisch einen Webser
ver benachrichtigt, wenn der Anwendungscode feh lsch lägt. Sie können auch Messwerte
der iPhone-Anwendung erfassen und an den Server senden, um die Anwendung schnel ler
und einfacher verwendbar zu machen.
Dank Se rverAcces sübj ect stehen alle diese Möglichkeiten jetzt auf einfache Weise für
iPhone-Web-Apps zur Verfügung.
209
Einführung in JSON
JSON (JavaScript Object Notat ion) ist ein bemerkenswertes Konzept. Damit können Sie Ja
vaScript-Objekte und -Arrays in Strings umwandeln, die sich über ein Netzwerk übergeben
oder in einer Datenbank speichern lassen. Später können diese Strings dann auf einem
anderen Computer oder nach dem Abruf aus der Datenbank in ihrer ursprünglichen Form
wiederhergestellt werden. Die Fähigkeit, JavaScript-Objekte und -Arrays zu serialisieren
und wieder zu expandieren, eröffnet ganz neue Möglichkeiten. ln diesem Anhang lernen
Sie die API (Applicat ion Programmer Interface) einer weiträumig akzeptierten JSON-Bib
liothek kennen und sehen in einfachen Beispielen, wie diese Bibliothek angewendet wird.
A.l ABSCHNITT 1: HINTERGRUND
Die Übergabe von Informationen von einem System zum anderen ist stets ein Problem.
Das gilt vor allem für die Entwicklung von Webanwendungen, denn hier kann der Server in
praktisch jeder möglichen Sprache geschrieben werden und auf den unterschiedlichsten
Arten von Computern laufen. XML war eines der ersten Formate, das sich nicht um Gerät,
Betriebssystem und Sprache kümmerte und damit dieses Problem lösen sol lte, und es er-
Anhang A Einführung in JSON
fü llt in vielen Gebieten auch durchaus seinen Zweck. Für die Datenübertragung ist XML
j edoch des Guten zu viel, vor allemangesichtsder geringen Mengen an Informationen, die
gewöhnlich mit AJAX gesendet werden. Wenn Sie einfach nur ein Array aus Zahlen oder
eine Schlüssel-Wert-Zuordnung senden wollen, ist XML zu aufwendig. Das Problem wird
nicht durch die Erfindung einerneuen Technologie gelöst, sondern durch die Nutzung von
Fäh igkeiten, die bereits in Interpretersprachen schlummern.
Alle wichtigen Interpretersprachen mit loser Typisierung weisen eine Art ev a 1-Funktion
auf, die Strings so ausführt, als wären sie Quel lcode. Dies ist eine sehr leistungsfähige,
aber auch gefährliche Fähigkeit, denn wenn sie falsch eingesetzt wird, kann sie eine An
wendung für Hacker und jede Form von Missbrauch öffnen. Daneben können in allen
wichtigen Interpretersprachen mit loser Typisierung Arrays und Objekte auch ohne den
Aufruf eines lnstanziierungs-Schlüsselworts wienewerstel lt werden.
Wenn Sie sich Java Script-Code ansehen, können Sie schnell erkennen, wie ein Array erstellt
wird. Das erste Beispiel zeigt einen obj ektorientierten Ansatz:
var array = new Array () ; array.push(5); array.push(13 ) ; array.push( 'hel l o ' ) ;
Das zweite Beispiel ist nicht obj ektorientiert:
var array = [5, 13, ' hel l o 'J:
Das Ergebnis ist in beiden Fäl len gleich. Es ist j edoch das zweite Beispiel, das uns für unse
re Erörterung von JSON interessiert. Zusammen mit der Mögl ichkeit, Strings in JavaScript
wie Code auszuf ühren, wird durch diese Vergehensweise mit JSON möglich.
Der folgende Code erstellt einen Zeichenstring in der Form, die ein Programmierer ver
wendet, um mit der Vergehensweise aus dem zweiten Beispiel ein Array anzulegen. Er
stellt wird hier nicht das Array selbst, sondern eine Beschreibung des Arrays.
var someStr i ng = " [ 5, 13, 'hell o'J": II Wert et den St ring aus var array = eval( someStr i ng ) ;
ln der letzten Zeile wird der String als JavaScript-Quellcode ana lysiert, dieser JavaScript
Code interpretiert und ausgeführt. Der String befindet sich in diesem einfachen Beispiel
in derselben Anwendung wie der Aufruf voneva l, weshalb dieser Vorgang eigentlich un-
212
Eine JSON-API für JavaScript
sinn ig ist. Wenn der String jedoch aus dem Objective-C-Teil einer QuickConnectiPhone
Anwendung stammt oder, wie es in herkömmlichen Anwendungen der Fal l ist, von einem
Server, dann ist dieser Aufruf von ev a 1 sehr viel sinnvoller.
Obj ekte werden ähn lich erstellt. Bei dem folgenden objektorientierten Ansatz wird ein
Obj ekt angelegt und mit Attributen versehen:
var object = new Object(); object.width = 5: object.height = 13: object.message = ' he l lo ' :
Der entsprechende nicht objektorientierte Ansatz sieht wie folgt aus:
var object = { "wi dth":5," height " :l3, "message ":"hello"l:
Im Folgenden sehen Sie den JSON-Code:
var someStr i ng = '{"width" :5," height ": l 3, "message":" hello " } ': II Wertet den String aus var object = eva l (someStr i ng);
Dies ist zwar der Kern von JSON, doch dies selbst zu implementieren, birgt Gefahren. Wenn
der String beispielsweise vom JavaScript- zum Objective-C-Teil einer QuickConnectiPhone
Anwendung übergeben wird und komplexe Anweisungen enthält, ist es möglich, damit
den gesamten Inhalt der Festplatte zu löschen.
Um dieses Sicherheitsproblem zu lösen, w urden bereits JSON-Bibliotheken entwickelt.
Diejenige f ür die JavaScript-Seite J son2 in der Dateijson2js. J s on2 ist der am häufigsten
eingesetzte JSON-Parser in JavaScript. Da Sie ständ ig Daten an den Objective-C-Teil von
QuickConnectiPhone-Anwendungen übergeben und von dort empfangen, müssen Sie
mit der API dieser Bibliot hek vertraut sein.
A.2 ABSCHNITT 2 : EINE JSON-API FÜR JAVASCRIPT
Die in Tabelle A.1 vorgestellte API J son2 ist sehr einfach und überschaubar. Sie besteht aus
nur zwei Funktionen. Die eine wandelt ein Objekt oder ein Array in einen String um, die
andere konvertiert Strings in Obj ekte. Die erste dieser Funktionen heißt s tri ng i fy.
213
Anhang A Einführung in JSON
Funktion Parameter
JSON. st ri ngify (entity ,
rep l acer ,
space,
l inebrea k )
JSON.pa r se
Erforderliche Parameter:
ent i t y - Das JavaScript-Objekt, -Array oder -Basiselement, das
konvertiert werden soll
Optionale Parameter:
rep l acer-Eine Funktion oder ein Array, mit dem Sie die stan
dardmäßige Stringerstellung für die mit den Schlüsseln der
JavaScript-Entitäten verknüpften Werte überschreiben können
spa ce-Eine Zahl oder ein Zeichen wie • \ t ' oder   zur
Einrückung von JavaScript-Entitäten, die als Werte mit Schlüsseln
in anderen Entitäten gespeichert sind
l i neb rea k - Zeichen, die das Standardzeichen • \ n' über
schreiben, z.B .• \ r \ n 'oder <b r I>
Erforderliche Paramter:
( s tri ng . rev i ver ) s t ri ng - Der JSON-String, der in ein Java-Obj ekt oder -Array
umgewandelt werden soll
Tabelle A.1: Die J son2-API
rev i ve r - Eine Funktion mit dem umgekehrten Verhalten des
Replacers in der Methode st r i ng i fy
Die Funktion st r i ng i f y weist mehrere Parameter auf, aber für QuickConnectiPhone
brauchen Sie nur den ersten. Dabei handelt es sich um das Obj ekt oder Array, das in einen
String umgewandelt werden sol l. Im Folgenden sehen Sie dazu ein allgemeines Beispiel:
var JSONStr i ng = JSON.str i ngify( object ) ;
Die Umwandlung von Strings in Objekte ist genauso einfach:
var object = JSON. parse(someStr i ng) ;
Arrays werden auf genau die gleiche Weise behandelt .
Abbildung A.1 zeigt beispielhaft ein Ergebnis, nachdem ein Objekt in einen String umge
wandelt, zurück in ein Objekt konvert iert und sein Attributs i ze ausgegeben wurde. Ein
vollständiges Beispiel zu r Verwendung von Json2 zur Stringumwandlung und Analyse
von Objekten fi nden Sie im Beispiel JSONData Examp l eim Verzeichnis iPhone Examples/ JSONDataExample des QuickConnectiPhone-Downloads. Dieses Beispiel zeigt sehr an
schau lich das Zusammenspiel von JSON und AJAX. Es lädt in JSON verpackte Serverdaten
214
Eine JSON-API für JavaScript
und konvertiert diese dann schlussendl ich in JavaScript-Objekte und stellt diese dar. Mehr
Informationen zu diesem Beispiel finden Sie unter http:llquickconnect.pbworks.com/AJAXand-JSON, -A-Qu ickConnect-exa mple.
()Q() obj ectj SON_example.htm l
~ ~ fi le:{{{Users{leebarney/Docu ments/bo -(~· Google ~ »
CD JavaDocs Sourceforoe ... ickConne:ct »
Serialized
{"sizc·•:4 .7,"couot'·:3}
inflatedObjects' size
4.7
h
~ Abbildung A.1: Das Ergebnis nach der String
umwandlung und Rückkonvertierung eines Objekts
ln JSONData Examp l e finden Sie auch ein Beispiel zu Arrays, das zeigt, w ie Sie Arrays mit
J son2 in einen String umwandeln und zurückkonvertieren.
Für beide Anwendungsfä lle werden die üblichen Begriffe serialize (seria lisieren) und inflate (wörtlich »aufblasen«, also erweitern) für die Ergebnisse der Funktion st r i ng i fy bzw.
parse verwendet.
M it der Bibliothek J son2 können Sie auch Basisele
mente (Primitives) wie Zah len übergeben. Auch Strin
gobjekte werden korrekt gehandhabt. Dies gi lt j edoch
nicht für al le JSON-Bibliotheken in al len Sprachen. Mit
der Bibl iothek J son2 können Sie beliebige Elemente
korrekt in Strings umwandeln und zurückkonvertieren.
Auch die JSON-Bibliothek für Objective-C handhabt
Primitives und Strings richtig.
~ Abbildung A.2: Eine Liste von Vorschaubildern erstellt mit
JSON und AJAX im JSONDataExample
215
Anhang A Einführung in JSON
A.3 ZUSAMMENFASSUNG
JSON ist eine wunderbare Möglichkeit zur Übergabe von Informationen und völl ig unab
hängig von Gerät, Betriebssystem und Sprache. Es gibt kostenlose Open-Source-Parser für
alle üblichen Sprachen. Bei manchen Sprachen (z.B. PHP) ist ein solcher Parser sogar im
Lieferumfang enthalten.
Die in QuickConnectiPhone entha ltene Bibliothek Js on2 ist einfach zu verwenden und
ermöglicht es Ihnen, Daten an den Objective-C-Teil einer hybriden Web-App zu senden
und von dort zu empfangen.
216
Evolution von QuickConnectFamily
Da sich Qu ickConnectiPhone noch in einem frühen Entwicklungsstadium befindet, un
terliegt es häufigen Änderungen. Daher ist es sehr w ichtig, die Entwicklung zu beobach
ten, um keine Aktualisierung zu verpassen. Tabelle 8.1 zeigt, was am 22. Februar 2010 zum
Download zur Verfügung stand. Mehr Informationen und die aktuellste Fassung der Road
map finden Sie auch unter http:llquickconnect.pbworks.com!Porting-Roadmap.
Ja bedeutet, dass das betreffende Merkmal im Lieferumfang enthalten ist, ln der Entwick
lung heißt, dass zurzeit an der betreffenden Funktion gearbeitet wird. Eine Funktion mit
dem Vermerk Entwicklung geplant ist möglich, aber noch nicht in der Entwicklung. Dagegen
bedeutet Nicht möglich, dass die betreffende Funkt ion auf dem Gerät nicht zur Verfügung
steht. Nur mit einem Strich versehene Tabellenzel len zeigen an, dass zum Zeitpunkt der
Drucklegung dieses Buches noch nicht an dem betreffenden Merkmal gearbeitet wird.
HINWEIS
Windows und Windows Mobile sind in Tabelle 8.1 nicht aufgeführt, da die Entwicklung
dafür zwar geplant ist, zurzeit aber noch nichtsdarangetan wird.
Anhangs Evolution von QuickConnectFamily
iPhone Android Mac linux Symbian
Geoortung Ja Ja Nicht Nicht
möglich möglich
Besch Ieu nigungs- Ja Ja ln Ent-
messer wicklung
Vibration Ja Ja Nicht Nicht
möglich möglich
Ad-hoc-Netzwerke Ja Entwick- Ja Entwick- Entwick-
lung lung lung
geplant geplant geplant
JavaScript-Datenbank- Ja Ja Ja Ja ln Ent -
w rapper (SQLite) w icklung
Wrapperfü r Ja Ja Ja Ja ln Ent -
installierte native w icklung
Datenbank (SQLite)
AJAX-Wrapper Ja Ja Ja Ja ln Ent -
w icklung
Drag&Drop- Ja Entwick- Ja
Bibliothek lung
geplant
Netzwerk über Entwick- Entwick-
Synchron isierungs- lung lung
kabel geplant geplant
Kamerazugriff ln Ent - Ja
wicklung
Geoortung in ln Ent -
Bildern wicklung
Systemsounds Ja Ja Ja Entwick- Entwick-
(abspielen) lung lung
geplant geplant
Audiodateien Ja Ja Ja Entwick-
auf nehmen/ lung
abspielen geplant
218
Definitionen
Native Datums-/ Ja Nicht Nicht Nicht Nicht
Uhrzeitauswahl möglich möglich möglich möglich
Eingebettete Ja ln Ent- Ja Entwick- Entwick-
Google-Ka rten wiekJung Jung lung
geplant geplant
Diagramme und Ja ln Ent- Ja ln Ent- ln Ent-
Grafiken wiekJung wiekJung w iekJung
Tabelle 8.1: Stand der QuickConnectFamily-Entwicklung am 23. Februar 2009
8.1 Definitionen
Geoortung - Abruf der aktuellen GPS-Koord inatendaten
Beschleunigungsmesser - Abruf der Änderungen an der Geräteausrichtung in x-, y- und
z-Koord inaten
Vibration - Lässt das Gerät vibrieren
Ad-hoc-Netzwerke - Sucht nach anderen Geräten in der Nähe, die dieselbe Anwendung
ausführen, und kommuniziert mit ihnen
JavaScript-Datenbankwrapper (SQLite) - Verwendung der integrierten HTML s-Daten
bank
Wrapperfür installierte native Datenbank (SQLite)-Verwendung der mit der Anwendung
ausgel ieferten SQLite-Daten ba n k
AJAX-Wrapper - Eine einfach zu verwendende AJAX-Bibl iothek für den Abruf von Daten
über das Netzwerk
Drag&Drop-Bibliothek - Eine einfach zu verwendende Bibliothek, über die der Benutzer
Bildschirmelemente versch ieben, drehen und in der Größe ändern kann
Netzwerk über Synchronisierungskabel - Greift über das Synchronisierungskabel auf den
Desktopcomputer zu und überträgt darüber Daten
Kamerazugriff -Aufnahmeund Speicherung von Bildern
Geoortung inBildern -Greift auf Geoortungsdaten zu, die in den mit dem Gerät aufge
nommenen Bi ldern eingebettet sind
Systemsound (abspielen) - Gibt kurze Klänge wieder (weniger als fünf Sekunden)
Audiodateien aufnehmen/abspielen - Nimmt Aud iodateien mit dem Gerät auf und gibt
diese sowie mit der Anwendung ausgelieferte Audiodateien w ieder
219
Anhangs Evolution von QuickConnectFamily
Native Datums-/ Uhrzeitauswahl - Zeigt die Objectice-C-Eiemente zur Datums- und Uhr
zeitauswah l statt der eingeschränkten JavaScript-Varianten an
Eingebettete Google-Karten - Zeigt in Ihrer Anwendung statt der Standardkarten benut
zerdefinierte Google-Karten oder die Map-Anwendung an
Diagramme und Grafiken - Eine einfach zu verwendende Bibl iothek zur Anzeige von Lini
en-, Balken-, Torten- und anderen Diagrammen
220
Stichwortverzeichnis
Stichwortverzeichnis
A abort 199 accel 107 ADC (Apple Developer
Connection) 26 add 46 Anonyme Funktionen 160 Ansichten 73 Ansichtsanwendungs-
controller 58 Anweisungen, vorbereitete 156 Anwendungen
BrowserAJAXAccess 188 BrowserDBAccess 149 Dialogfeld Alert 19 Immersionsanwendungen 8o m it nicht listengest ützter
Ansicht 75 Anwendungscontroller so Anzeige
Auswahlfelder 110 Karten in QuickConnect
JavaScript-Anwendungen 129 API f ür Drag&Drop/Skalierung/
Drehung 91 application DidFin ish
launching 31 Arrays
Erstellen 212 ln 5trings konvertieren 214 passThroughParameters 161 retVal 183
Asynchron 59 Aufnahmen
Beenden 10 8 Wiedergeben 108
Auswahlfe lder Anzeigen 110 Objective-C 120
8 BCFs (Business Control
Functions) 44 Benutzereingaben validieren 44 Berührbare Bilder 75 BrowserAJAXAccess 188 BrowserDBAccess 149 Business Control Functions
(BCF) 44
c calculateSolutionsBCF 47 caiiFunc 62 changeView 73 checkNumbersVaiCF so check5ecurity 207 code (Attribut) 168 (55-Transformationen 82 cube 78
D Dashcode
QuickConnectiPhoneVorlage 17
Übergänge 76 Verzeichnisse 24
DataAccessObject 152 Beispielcode 170 Database-Objekt 162 dbAccess 161 generatePassThroughPara-
meters 161 getData 161 Met hoden 152 Native 5Qlite-Daten-
banken 157 passThroughParameters
Array 162 setData 161 5QLError-Objekt 167
5QLResult5et-Objekt 166 5QLResult5etRowlist 166 5QLTransaction-Objekt 164 WebKit -Datenbanken 159
DataAccessObject.js 152 Database-Objekt 162 Dateien
DataAccessObj ectjs 152 Kopieren 23 5erverAccessObject.js 192
Datenabruf 44 Datenbankfelder 150 Datenbankzugriff
Beispielcode 170 BrowserDBAccess 149 Database-Objekt 162 Datenbankterminologie 150 dbAccess 161 generatePassThroughPara-
meters 161 getData 161 getDeviceData 172 getNativeData 172
makeCa ll 173 Native Datenbanken 172 Native 5Qlite-Daten-
banken 157 passThroughParameters-
Array 162 5endDBResultVCO-Objekt 182 setData 161 setNativeData 172 5QLError-Objekt 167 5Qlite3-APJ 175 5QLResult5et-Objekt 166 5QLResult5etRowlist 166 5QLTransaction-Objekt 164 Überblick 149 WebKit-Datenbanken 151, 159
Datensätze 150
Stichwortverzeichnis
Datenzugriff über das Netzwerk BrowserAJAXAccess 188 displaySiteDataVCF 193 getData 190, 197 getSiteDataBCF 192 makeCall 197 onreadystatechange 204 SCF (Security Control
Functions) 208 ServerAccessObject 190 setData 191, 197 Überblick 187 XMLHttpRequest-Objekt 202
dbAccess 161,169 Delegates 29 deleteScoreBCF 157 Dialogfeld Alert 19 dispatchToBCF 58 dispatchToECF 64 dispatchToVaiCF 54 dispatchToVCF 62 displayScoresVCF 155.158 displaySiteDataVCF 193 dissolve 77 doCommand 117,124, 135,183 DollarStash 81 done 87 dragAndGesture 91 Drag&Drop 69
Hüpfende Elemente 84 Module 90
Drehfunkt ionen 89 Drehu ng 94
E ECF (Error Control Functions) 47 Einbetten
Google Maps 129 Webinhalt (QuickConnect-
iPhone) 33 Elemente (Bibliot hek) 71 entryECF 47 Entwicklungsstand
QuickConnectiPhone 217 Entwicklungswerkzeuge
QuickConnectiPhone 217 eval 51,212 executeSQL 164,169
222
F fade 78 Feh leranwendungscontroller 63 flip 78 Fra meworks 42 Fremdschlüssel 150 FrontController-API 45 Funktionen
G
Anonyme Funktionen 160 SCF (Secu rity Control
Functions) 208
generatePassTh roughPa rameters 161
Geräteaktivierung JavaScript 103 Objective-C 110
Gesten 69, 87 Gestu reEvent 87 getAIIResponseHeaders 199 getData 153,154.161,190,197 getDeviceData 172 getGPSLocation 109 getlnstance 120 getNativeData 153.158.172 getResponseHeader 199 getSiteDataBCF 192 goForward 74 Google-Karten anzeigen 129 goSub 75 GPS
JavaScript 109 Objective-C 116
Gruppen (Xcode) 23
H hand leRequest 45,53 ha nd leReq uestCom pletion From
Native 184 HIG (Human Interface
Guide) 68 HistoryExam ple 71 Hüpfende Elemente 84
Immersionsanwendungen 8o lnfoWlndow 134,147 initWithFrame 135 insertiD 166 lnstanziierung 27 isOraggable 93 item 167
J JavaScript
Geräteaktivierung 104 Modularität 41 scroll 138
JSON (JavaScript Object Notat ion) 108, 196 Json2-API 214 Überblick 211
Json2-API 214 JSONStringify 183
K Ka rten
ln QuickConnect-JavaScriptAnwendungen anzeigen 129
QuickConnect-Karten-modul 134
Vergrößern 142 Klassen
DataAccessObject-Methoden 152
Native SQLite-Daten-banken 157
QuickConnectView-Controller 33
Singleton-Klassen 120 SQLiteDataAccess 175 WebKit -Daten banken 159
Konvertierung zwischen Objekten und Strings 214
Kopieren von Dateien 23
L length 167 Listengestützte Schnittst ellen 71 loadView 34
M makeCall 104,173,197 makeChangeable 90,93 makeDraggable 90 mapCommands 114 mapCommandToCo 126 MapView 134 math 46 Medizinische Bildgebungs
anwendungen 8o message 168 Modularität
Beispiel für das JavaScriptFramework QuickConnect 43
Implementierung in QuickConnectiPhone 53
JavaScript 41 Steuerfunktionen 44
Module Definition 42 Drag&Drop 90 Drehung 94 Skalierung 94
moveX\ andY 144
N Native Datenbanken 172
getDeviceData 172 getNativeData 172 makeCall 173 SendDBResultVCO-Objekt 182 set NativeData 172 SQUte3-API 175 SQLite-Datenbanken 157
NSlog 125
0 Objective-C 26
Auswahlfelder 120 Geräteaktivierung 111
Objekte instanziieren 27 QuickConnectiPhone-
Anwendungsstruktur 29 QuickConnect iPhone
Architektur 120 QuickConnect-Karten
modul 134
Objekte Erstellen 213 lnstanziieren 27 in Strings konvertieren 214 Strings in Objekte
konvertieren 214 oldScale 93 ongesturechange 99 onreadystatecha nge 201, 204 ontouchchange 85 open 200 openDatabase 162
p parse 214 passThroughPara meters
Array 162 pathForResource
ofType 36 Pin 134,139 play 105 playSound 105 prepareDrag 94 prepareGest ure 98 Primärschlüssel 150 Prinzipai-Delegate-Beziehung 29 Prinzipale 29 Protokolle 30 Provisioning 26 Proxys 29 push 77
Q QCCommandObject 124 QuickConnect
Karten anzeigen 129 Modularität 42
QuickConnectFamily-lnstaller 18 QuickConnectiPhone
Entwicklungsstand 217 Modu lares Design 53 Objective-C -Anwendungs-
struktur 29 Objective-C
Implementierung 120 Webinhalt einbetten 33
QuickConnectiPhone-Vorlagen Dashcode 17 Xcode 21
QuickConnect-Kartenmodul 134 Qu ickConnectViewControl ler 33
Stichwortverzeichnis
R readyState 201 Rekursion 62 requestHandler 207 responseText 202 responseXML 202 retVal-Array 183 revolve 78 rows 166 rowsAffected 166
s SCF (Security Control
Functions) 208 Schalter 70 Schnittstel len
Ansichten 73 CSS-Tra nsformationen 82 listengestützte Schnitt-
stellen 71 scroll 138 Security Control Fundions
(SCF) 208 send 201 SendDBResultVCO-Objekt 182 sendloc 118 ServerAccessObject 190
displaySiteDataVCF 193 getData 190, 197 getSiteDataBCF 192 makeCall 197 Methoden 192 onreadystatechange 204 setData 191, 197 XM LHttpRequest-Objekt 202
ServerAccessObject.js 192 setData 153, 161,191, 197 setMapLatlngFrameWith-
Description 146 setNativeData 153, 172 SetReq uestHeader 201 setStartlocation 85 shouldStartl oadWithReq uest 111
showDateSelector 110 showMap 132 showPickResults 110 Singleton-Klassen 120 singleTouch 140 Skalierung 94 slide 77
223
Stichwortverze.:ic::.:h::n.::is ____________________ __
SQLError-Objekt 167 SQlite3-API 175 sqlite3_bind_blob 178 sqlite3_bind_double 178 sqlite3_bind_int 179 sqlite3_changes 176 sqlite3_close 175 sqlite3_column_blob 177 sqlite3_column_bytes 177 sqlite3_column_count 176 sqlite3_column_double 177 sqlite3_column_int 177 sqlite3_column_name 176 sqlite3_column_text 177 sqlite3_column_type 176 sq lite3_ errmsg 175 sqlite3_ finalize 178 sqlite3-0bjekt 175 sqlite3_open 175 sqlite3_prepare_v2 176 sqlite3_step 176 sqlite3_stmt 175 SQliteDataAccess 175 SQlite-Datenba nken
Beispielcode 170 Database-Objekt 162 dbAccess 161 generatePassThroughPara-
meters 161 getData 161 Native SQlite-Daten
banken 157 passThrough Parameters-
Array 162 setData 161 SQLError-Objekt 167 SQLResultSet-Objekt 166 SQLResultSetRowlist 166 SQLTra nsaction-Objekt 164 WebKit-Datenbanken 151,159
SQLResultSet-Objekt 166 SQLResultSetRowlist 166 SQLTransaction-Objekt 164 Standardverhalten 69 status 202 statusText 202
224
Steuerfunktionen 44 stri ngByEva I uati ngJ ava Scri pt-
FromString 184 stringify 213 Strings konvertieren 214 Subviews 72 swap 78 Synchron 59 Systemsounds
T
ln Objective-C abspielen 115 JavaScript 104
Tabellen 150 terminatePiaying 108 touch 83 Touch 83 touchesBegan 142 touchesMoved\
withEvent 137.145 transaction 163,169 Transformationen 82 translate 86
u Übergänge 76 UIWebView
API 35 Klasse 33
Unteransichten 35 Unternehmensanwendungs
controller s8
V VaiCF (Validation Control
Functions) 44 VCF (View Control Functions) 44 Verschiebung 99 Verzeichnisse 24 Vibrationen 105, 112 Vorbereitete Anweisungen 156 Vorlagen
Dashcode 17 QuickConnectiPhone 21
w WebKit-Datenbanken 159
Beispielcode 170 Database-Objekt 162 dbAccess 161 generatePassThroughPara-
meters 161 getData 161 passThroughPa rameters-
Array 162 setData 161 SQLError-Objekt 167 SQLResultSet-Objekt 166 SQLResultSetRowlist 166 SQLTransaction-Objekt 164
webKitTransform 83 webMapView 136 Wiedergabe
X
Aufnahmen 108 Systemsounds 115
Xcode Gruppen 24 QuickConnect-Vorlagen 21
XMLHttpRequest 199
z Zeiger 26 Zoom in Karten 142 Zukünftige Entwicklung
QuickConnectiPhone 217