Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 Hello iPhone
2 Die Reise nach iOS
3 Sehen und anfassen
4 Alles unter Kontrolle
5 Daten, Tabellen und Controller
6 Models, Layer, Animationen
7 Programmieren, aber sicher
8 Datenserialisierung und Internetzugriff
9 Multimedia
10 Jahrmarkt der Nützlichkeiten
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
Apps programmieren für iPhone und iPad von Klaus M. Rodewig, Clemens Wagner
Das umfassende Handbuch
Buch: Apps programmieren für iPhone und iPad

Apps programmieren für iPhone und iPad
Rheinwerk Computing
1172 S., geb., mit DVD
49,90 Euro, ISBN 978-3-8362-2734-6
Pfeil 8 Datenserialisierung und Internetzugriff
Pfeil 8.1 Ich packe meine Texte
Pfeil 8.1.1 Serialisierung von Zeichenketten
Pfeil 8.1.2 Zeichenkodierungen
Pfeil 8.1.3 Unicode und UTF-8
Pfeil 8.1.4 Die Zeichenkodierung erkennen
Pfeil 8.1.5 Zeichenketten konvertieren
Pfeil 8.2 JSON und die URLonauten
Pfeil 8.2.1 Das JSON-Format
Pfeil 8.2.2 Einfacher YouTube-Zugriff mit JSON
Pfeil 8.2.3 URLs erstellen
Pfeil 8.2.4 JSON-Dokumente schreiben
Pfeil 8.2.5 Verwendung des JSONKits als Parser
Pfeil 8.3 XML
Pfeil 8.3.1 XML in Kürze
Pfeil 8.3.2 Property-Listen
Pfeil 8.3.3 SAX
Pfeil 8.3.4 DOM und XPath
Pfeil 8.3.5 Der Tag der Entscheidung
Pfeil 8.4 Daten, Daten, ihr müsst wandern
Pfeil 8.4.1 Synchrone Kommunikation
Pfeil 8.4.2 Komplexe Anfragen
Pfeil 8.4.3 Auf dem Webserver nichts Neues
Pfeil 8.4.4 Asynchrone Kommunikation
Pfeil 8.4.5 Große Datenmengen der Übertragung
Pfeil 8.4.6 Passwortabfragen
Pfeil 8.4.7 Sicher kommunizieren mit TSL (SSL)
Pfeil 8.4.8 Hier geht die POST ab
Pfeil 8.4.9 Dateiupload
Pfeil 8.4.10 Überprüfung der Erreichbarkeit
Pfeil 8.5 Karten
Pfeil 8.5.1 Karten darstellen
Pfeil 8.5.2 Koordinatensysteme
Pfeil 8.5.3 Geokoordinaten bestimmen
Pfeil 8.5.4 Eigene Kartenbeschriftungen
Pfeil 8.5.5 Routen

Rheinwerk Computing - Zum Seitenanfang

8.5KartenZur nächsten Überschrift

Das Beispielprojekt SiteSchedule kann außerdem die Baustellen in einer Karte anzeigen. Dazu verwendet es das MapKit. Dieses Framework erlaubt die Anzeige von Karten mit selbstdefinierten Anmerkungen. Bis iOS 5 stammte das Kartenmaterial von Google; seit iOS 6 verwendet Apple das Material der Firma TomTom, weswegen die Karten ein anderes Design haben.

Ein positiver Effekt dieser Umstellung ist die Aufwertung der Karten-App zu einem vollwertigen Navigationssystem mit gesprochenen Wegbeschreibungen. Außerdem bietet sie für einige Städte eine 3D-Ansicht an. Wenn Sie auf Satelliten- und 3D-Darstellung umschalten, können Sie beispielsweise einen faszinierenden Rundgang durch die Häuserschluchten von New York unternehmen. Die Umstellung erfolgt für die Entwicklung indes vollkommen transparent; das heißt, die APIs sind im Wesentlichen gleich geblieben.


Rheinwerk Computing - Zum Seitenanfang

8.5.1Karten darstellenZur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse MKMapView erlaubt es Ihnen, Karten in Ihrer App anzuzeigen. Binden Sie einfach einen solchen View in eine Ihrer View-Hierarchien ein, um eine Karte anzuzeigen. Dieser View unterstützt bereits eine Ausschnittauswahl per Scrollen und Zoomen, inklusive der Doppel-Tap-Geste, sowie die Anzeige des aktuellen Standortes.

Abbildung

Abbildung 8.27 Die Einstellungsmöglichkeiten von Karten

Diese Optionen können Sie über den Attributinspektor des Interface Builders einstellen (siehe Abbildung 8.27). Dort können Sie außerdem die Darstellungsart auswählen. Hierfür stehen Ihnen unter der Einstellung Type drei Auswahlmöglichkeiten zur Verfügung:

Tabelle 8.18 Die Darstellungsarten des Mapviews

Auswahl Beschreibung

Map

In der Kartendarstellung zeigt der View eine beschriftete Straßenkarte mit Orts- und Straßennamen sowie Sehenswürdigkeiten an.

Satellite

Die Satellitenansicht stellt das Gelände als Satellitenaufnahme ohne Standardbeschriftungen dar.

Hybrid

Die Hybriddarstellung zeigt die Satellitenansicht mit den Beschriftungen und Wegen aus der Kartendarstellung an.

Über die Property mapType können Sie die Darstellungsart auch aus Ihrem Programmcode heraus verändern. In Abbildung 8.28 sehen Sie den gleichen Kartenausschnitt in den drei unterschiedlichen Darstellungsarten.

Abbildung

Abbildung 8.28 Die Darstellungsarten des Mapviews

Der Mapview kann auch die aktuelle Position des Gerätes auf der Karte anzeigen. Da das allerdings eine sensible Information ist, fragt iOS den Nutzer für jede App über einen Alertview nach, ob die App seinen aktuellen Standort verwenden darf.

Die Anzeige des Standortes erfolgt dabei über einen blauen Punkt, der in einem weißen Kreis liegt. Der animierte hellblaue Ring um den aktuellen Standort (siehe Abbildung 8.29) dient lediglich zur Hervorhebung. Wenn iOS den Gerätestandort bestimmt, zeigt das die Statusleiste links neben dem Batteriesymbol durch eine Kompassnadel an. Der Mapview aktualisiert den Gerätestandort automatisch. Wenn sich der Nutzer also mit dem iPhone weit genug fortbewegt, ändert auch der blaue Punkt seine Position auf der Karte.

Abbildung

Abbildung 8.29 Anzeige des aktuellen Standortes


Rheinwerk Computing - Zum Seitenanfang

8.5.2KoordinatensystemeZur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse MKMapView ist eine Unterklasse von UIView und basiert somit auf dem Koordinatensystem von Cocoa Touch, das jedoch für Karten sehr unpraktisch ist. Um einen Punkt auf der Erdoberfläche anzugeben, verwendet man geografische Koordinaten, die aus einer Breiten- und einer Längengradangabe bestehen. [Anm.: http://de.wikipedia.org/wiki/Geographische_Koordinaten] Dabei sind beide Werte Winkelangaben, deren Nulllinie der Äquator beziehungsweise der Nullmeridian ist. Der Nullmeridian ist ein festgelegter Kreis um die Erde, der sowohl durch den Nord- und den Südpol als auch durch den Mittelpunkt des Teleskops des Königlichen Observatoriums von Greenwich, London, verläuft.

In Cocoa Touch können Sie diese Koordinaten durch eine Variable der Struktur CLLocationCoordinate2D darstellen, die die beiden Felder latitude und longitude für Breiten- und Längengrad bereitstellt. Die Angaben dieser Winkel erfolgen immer im Gradmaß. Beispielsweise hat der Kölner Dom die geografischen Koordinaten (50,941302°; 6,957189°). [Anm.: Die Angabe einer Koordinate erfolgt immer in (Breitengrad; Längengrad).]

Die Struktur MKCoordinateRegion dient zur Beschreibung eines Bereichs auf der Erdkugel, in dem eine geografische Koordinate den Mittelpunkt darstellt und zwei Winkel die Breiten- und Längenabweichung vom Mittelpunkt beschreiben. Diese Abweichungen beschreibt die Struktur MKCoordinateSpan. Der Bereich ähnelt bei der Draufsicht in den meisten Fällen einem Trapez, wie Abbildung 8.30 es darstellt. Dabei entspricht der Schnittpunkt der gestrichelten Linien dem Mittelpunkt.

Abbildung

Abbildung 8.30 Ein Bereich auf der Kugeloberfläche

Über geografische Koordinaten können Sie den angezeigten Kartenausschnitt eines Mapviews festlegen. Über die Property centerCoordinate können Sie beispielsweise den Mittelpunkt auslesen und ändern, und über setCenterCoordinate:animated: können Sie die Änderung auch mit einer Animation durchführen.

Über die Property region können Sie den Bereich auslesen und ändern. Dabei verwenden Sie jeweils Werte der besprochenen Struktur MKCoordinateRegion. Diese Property erlaubt Ihnen also die gleichzeitige Wahl des Mittelpunktes und der Skalierung der Karte. Über setRegion:animated: können Sie auch diese Änderung animieren lassen.

Über Geokoordinaten lassen sich aufgrund der Erdkrümmung nur sehr schlecht rechteckige Kartenausschnitte beschreiben. Dafür gibt es die Struktur MKMapRect, die ein Rechteck auf der projizierten Karte darstellt. Für diese Struktur stellt das MapKit verschiedene geometrische Funktionen bereit. Die Definition eines Kartenrechtecks über diese Struktur erfolgt analog zu CGRect über einen Ursprung und die Größe.

Das Beispielprojekt SiteSchedule bestimmt zu jeder Baustelle die geografischen Koordinaten und berechnet aus allen Koordinaten in der Property mapRect das kleinstmögliche Rechteck für die Anzeige. Dazu verwendet es die Funktion MKMapRectUnion, die das kleinste Rechteck berechnet, in dem die zwei übergebenen Rechtecke liegen.

- (void)updateMapRectWithCoordinate:  
(CLLocationCoordinate2D)inCoordinate
isFirst:(BOOL)inIsFirst {
MKMapPoint thePoint =
MKMapPointForCoordinate(inCoordinate);
MKMapRect theRect = MKMapRectNull;

theRect.origin = thePoint;
self.mapRect = inIsFirst ? theRect :
MKMapRectUnion(self.mapRect, theRect);
}

Listing 8.80 Berechnung des kleinsten Rechtecks

Die Methode updateMapRectWithCoordinate:isFirst: aus Listing 8.80 wandelt dazu zunächst die übergebene Koordinate über die Funktion MKMapPointForCoordinate in einen Punkt um. Dieser Punkt dient als Ursprung für ein Rechteck mit der Breite und der Höhe 0. Wenn es sich um die erste Koordinate in der Berechnung handelt, ist dieses Rechteck das Ergebnis der Berechnung, ansonsten berechnet die Methode die Vereinigung aus dem vorherigen Ergebnis mit dem neuen Rechteck. Nachdem die App alle Koordinaten eingerechnet hat, legt sie über die Methode setVisibleRect:animated: den Ausschnitt des Mapviews fest.


Rheinwerk Computing - Zum Seitenanfang

8.5.3Geokoordinaten bestimmenZur nächsten ÜberschriftZur vorigen Überschrift

Sowohl für die Berechnung des Kartenausschnitts als auch für die Anzeige der Baustellen auf der Karte muss die App die Geokoordinaten der Baustellen kennen. Dafür können Sie die Klasse CLGeocoder aus dem CoreLocation-Framework verwenden. Diese Klasse unterstützt sowohl die Berechnung von Geokoordinaten aus Adressen als auch die Umkehrung, bei der sie zu einer Koordinate eine Adresse bestimmt. Der Geocoder benötigt allerdings immer eine Internetverbindung, um Geokoordinaten oder Adressen zu bestimmen.

Er kann dabei die Geokoordinaten sowohl aus einem Dictionary mit den einzelnen Bestandteilen der Adresse als auch aus einer Zeichenkette bestimmen. Das Beispielprojekt SiteSchedule verwendet die erste Variante, da ja die Adressen der Baustellen schon fein säuberlich in Straße, Postleitzahl, Stadt und Land aufgeteilt vorliegen. Die Methode address der Klasse Site liefert die enthaltene Adresse als Dictionary für die Geokodierung:

- (NSDictionary *)address {
return @{(id)kABPersonAddressZIPKey: self.zip,
(id)kABPersonAddressCityKey: self.city,
(id)kABPersonAddressCountryCodeKey: self.countryCode,
(id)kABPersonAddressStreetKey: self.street};
}

Listing 8.81 Erstellung des Adress-Dictionarys für die Geokodierung

Die Schlüssel für das Dictionary stellt dabei das AddressBook-Framework bereit, und das Beispielprojekt bindet dieses Framework nur für diese Konstanten ein.

Sie dürfen zwar beliebig viele Geocoder-Objekte in einer App anlegen, allerdings sollten Sie niemals mehrere Anfragen gleichzeitig stellen. Da die Geokodierungsanfragen asynchron erfolgen, können Sie bei mehreren Anfragen also nicht einfach eine Schleife schreiben, die mehrere Anfragen direkt nacheinander abschickt.

Die Klasse MapViewController umgeht dieses Problem durch rekursive Aufrufe, indem sie eine Anfrage startet und die nächste Anfrage erst nach dem Ende der ersten stellt. Dazu verwendet sie die Property sites, die alle Baustellen enthält. Der Controller ermittelt jedoch die Koordinaten einer Baustelle nur, wenn sie noch keine hat, und speichert die ermittelten Koordinaten einer Baustelle in deren Core-Data-Entität ab.

Die Methode updateGeocoordinates: erhält als Parameter den Index der Baustelle, die sie als Nächstes verarbeiten soll. Sie ist dabei in drei Teile unterteilt. Die erste while-Schleife wertet die Baustellen ab dem Index aus, die bereits eine Geokoordinate haben. Dabei fügt sie diese Koordinate zum Kartenrechteck hinzu (siehe Listing 8.80) und kennzeichnet sie auf der Karte mit einem Pin. Wenn nach dem Durchlauf dieser Schleife die Variable theSite gleich nil ist, wurden alle Baustellen lokalisiert. Andernfalls hat die Schleife eine Baustelle ohne Geokoordinaten gefunden, und die Methode startet eine Lokalisierungsanfrage mit der Adresse der Baustelle.

- (void)updateGeocoordinates:(NSUInteger)inIndex {
NSUInteger theIndex = inIndex;
Site *theSite = nil;

while(theIndex < self.sites.count) {
theSite = self.sites[theIndex];
if(theSite.hasCoordinates) {
[self updateMapRectWithCoordinate:
theSite.coordinate isFirst:theIndex == 0];
[self addAnntationForSite:theSite];
theIndex++;
theSite = nil;
}
else {
break;
}
}
if(theSite != nil) {
[self.geocoder geocodeAddressDictionary:
theSite.address completionHandler:
^(NSArray *inPlacemarks, NSError *inError) {
if(inError == nil && inPlacemarks.count > 0) {
CLPlacemark *thePlacemark = inPlacemarks[0];
CLLocationCoordinate2D theCoordinate =
thePlacemark.location.coordinate;

theSite.coordinate = theCoordinate;
[self updateMapRectWithCoordinate:
theCoordinate isFirst:inIndex == 0];
[self addAnntationForSite:theSite];
}
else {
NSLog(@"error = %@", inError);
}
[self updateGeocoordinates:theIndex + 1];
}];
}
if(theIndex >= self.sites.count) {
[self.mapView setVisibleMapRect:self.mapRect
animated:YES];
[self.managedObjectContext save:NULL];
}
}

Listing 8.82 Aktualisierung der Geokoordinaten

Dazu verwendet sie die Methode geocodeAddressDictionary:completionHandler: des Geocoders. Die Blockfunktion, die das Ergebnis der Anfrage auswertet, erhält ein Array mit Objekten der Klasse CLPlacemark, wovon sie jedoch nur das erste Element verwendet. Geokodierungsanfragen müssen kein eindeutiges Ergebnis liefern, da Sie ja nicht unbedingt alle Details einer Adressanfrage angeben müssen. In der Regel sollte dieses Array allerdings nur ein Element enthalten.

Am Ende ruft die Blockfunktion erneut die Methode updateGeocoordinates: auf. Da der Indexwert bei dem erneuten Aufruf gegenüber dem aktuellen Aufruf jedoch immer höher ist, muss diese Rekursion enden, da irgendwann das komplette Array durchlaufen wurde. In diesem Fall setzt die Methode das sichtbare Rechteck des Mapviews und speichert die geänderten Koordinaten in der Datenhaltung.


Rheinwerk Computing - Zum Seitenanfang

8.5.4Eigene KartenbeschriftungenZur nächsten ÜberschriftZur vorigen Überschrift

Die Anzeige einer Karte ist in den meisten Fällen nur dann sinnvoll, wenn die App sie mit eigenen Daten anreichert. Sie können dafür zu einem Mapview Anmerkungen hinzufügen. Für solche Anmerkungen können Sie beliebige Objekte verwenden, sofern sie das Protokoll MKAnnotation implementieren. Dabei muss eine Implementierung allerdings nur die Methode coordinate zwingend bereitstellen, da sie die Position der Anmerkung auf der Karte als Geokoordinate angibt.

Das Beispielprojekt verwendet eine eigene Klasse namens Annotation für die Anmerkungen, die alle Methoden des Protokolls über die drei Propertys coordinate, title und subtitle implementiert. In der Property objectId speichert sie außerdem die Kennung der Site-Entität, zu der die Anmerkung gehört.

Die Klasse MKMapView stellt die vier Methoden addAnnotation:, addAnnotations:, removeAnnotation: und removeAnnotations: bereit, mit denen Sie die Anmerkungen einer Karte verwalten können. Außerdem können Sie über die Read-only-Property annotations alle Anmerkungen der Karte erfragen.

Der Mapview erzeugt für jede Anmerkung, die im sichtbaren Teil der Karte liegt, einen View zur Darstellung. Die Klasse des Views muss dabei eine Unterklasse von MKAnnotationView sein. Die Erzeugung der Views erfolgt über die Delegate-Methode mapView:viewForAnnotation:, deren Implementierung sehr ähnlich wie die Methode tableView:cellForRowAtIndexPath: der Datenquelle eines Tableviews ist.

Für die Anzeige der Anmerkungen verwendet das Beispielprojekt Views der Klasse MKPinAnnotationView, die an der Koordinate der Anmerkung eine Stecknadel anzeigen. Wenn Sie die Nadel antippen, erscheint darüber eine Sprechblase mit dem Titel und dem Untertitel. Auf der linken und rechten Seite können Sie jeweils einen View anzeigen lassen. Das Beispielprojekt verwendet hierzu zwei Buttons (siehe Abbildung 8.31). Außerdem unterstützt der Pin-Annotationview die Anzeige eines Bildes in der Sprechblase, wovon die Beispiel-App allerdings keinen Gebrauch macht.

Abbildung

Abbildung 8.31 Karte mit Anmerkungen

- (MKAnnotationView *)mapView:(MKMapView *)inMapView 
viewForAnnotation:(id<MKAnnotation>)inAnnotation {
MKPinAnnotationView *theView = nil;

if(![inAnnotation isKindOfClass:[MKUserLocation class]]) {
theView = (MKPinAnnotationView *)[inMapView
dequeueReusableAnnotationViewWithIdentifier:
@"Site"];
if(theView == nil) {
UIButton *theLeftButton = [UIButton
buttonWithType:UIButtonTypeInfoLight];
UIButton *theRightButton = [UIButton
buttonWithType:UIButtonTypeContactAdd];

theLeftButton.tag = 10;
theRightButton.tag = 20;
theView = [[MKPinAnnotationView alloc]
initWithAnnotation:inAnnotation
reuseIdentifier:@"Site"];
theView.pinColor = MKPinAnnotationColorRed;
theView.canShowCallout = YES;
theView.animatesDrop = YES;
theView.leftCalloutAccessoryView =
theLeftButton;
theView.rightCalloutAccessoryView =
theRightButton;
}
else {
theView.annotation = inAnnotation;
}
}
return theView;
}

Listing 8.83 Erzeugung der Views für die Anmerkungen

Bei der Erzeugung der Views müssen Sie noch einen Sonderfall berücksichtigen: Wenn die Karte den aktuellen Standort anzeigt, dann ruft der Mapview die Delegate-Methode mit einer Anmerkung der Klasse MKUserLocation zu dieser Koordinate auf. Sie können nun entweder einen View für den Nutzerstandort erzeugen oder einfach nil zurückgeben und so die Standardansicht, den blauen Punkt, anzeigen.

Für alle anderen Anmerkungen verwendet das Delegate Pin-Annotationviews. Die erzeugt es entweder neu, oder es verwendet einen bereits erzeugten, allerdings wieder freigegebenen View. Nach der Erzeugung initialisiert die Methode aus Listing 8.83 noch den linken und rechten Accessory-View mit jeweils einem Button. Außerdem setzt sie canShowCallout auf YES, damit der Pin auch die Sprechblase nach dem Antippen anzeigt. Das Setzen der Property animatesDrop auf YES bewirkt, dass der Mapview die Anzeige des Pins animiert.

Der linke Button in der Sprechblase zeigt einen Viewcontroller mit Informationen zu der Baustelle an, während der rechte Button zur Anzeige von Routen zu der Baustelle dient. Sie können für diese Aktionen entweder – wie bei jedem anderen Button auch – Action-Methoden konfigurieren oder die Delegate-Methode mapView:annotationView:calloutAccessoryControlTapped: verwenden. Der Vorteil der Delegate-Methode ist, dass sie Ihnen die Anmerkung mitliefert. Sie funktioniert allerdings nur, wenn der entsprechende Accessory-View eine Unterklasse von UIControl hat. Die Implementierung dieser Delegate-Methode in Listing 8.84 unterscheidet die beiden Buttons anhand ihres Tag-Wertes voneinander.

- (void)mapView:(MKMapView *)mapView 
annotationView:(MKAnnotationView *)inView
calloutAccessoryControlTapped:(UIControl *)inControl {
Annotation *theAnnotation = inView.annotation;
Site *theSite = (Site *)[self.managedObjectContext
objectWithID:theAnnotation.objectId];

if(inControl.tag == 10) {
ActivitiesViewController *theController =
[self.storyboard
instantiateViewControllerWithIdentifier:
@"activities"];

[theController setUnorderedActivities:
theSite.activities];
[self.navigationController
pushViewController:theController animated:YES];
}
// Ansonsten Route anzeigen...
}

Listing 8.84 Ausführung der Aktion für den linken Accessory-View

Da die Delegate-Methode die Anmerkung als Parameter erhält, kann sie über deren Property objectId das zugehörige Site-Objekt aus Core Data laden und damit den Viewcontroller für die Anzeige der Aktivitäten konfigurieren.


Rheinwerk Computing - Zum Seitenanfang

8.5.5RoutenZur nächsten ÜberschriftZur vorigen Überschrift

Über den rechten Button in der Sprechblase kann sich der Nutzer Routen von seinem aktuellen Standort zu der Baustelle anzeigen lassen. Diese Anzeige geschieht allerdings nicht in der App, sondern in der App Karten, die zu iOS gehört. In den Versionen vor iOS 6 mussten Sie die Karten-App über eine URL aufrufen. Seit iOS 6 stellt Apple mit der Klasse MKMapItem dafür eine komfortablere Zugriffsmöglichkeit bereit.

Zugriff auf die Maps-App ab iOS 6

Sie können unter iOS 6 die Karten-App aus Ihrem Programm heraus über die Klasse MKMapItem öffnen. Dabei stellen die Objekte dieser Klasse die Standorte auf der Karte dar, die Sie in der Karten-App darstellen wollen. Ein Map-Item basiert dabei entweder auf dem aktuellen Standort oder einer Ortsmarke, das sind Objekte der Klasse MKPlacemark. Diese Objekte können neben der Geokoordinate eine Reihe weiterer Informationen speichern, wie die Adresse oder die Höhe über dem Meeresspiegel.

Über den Convenience-Konstruktor mapItemForCurrentLocation können Sie ein Map-Item zum aktuellen Standort erzeugen, das keine konkreten Koordinaten enthält. Es dient der Karten-App zur Identifizierung des Gerätestandortes, und die Position seiner Markierung auf der Karte passt sich automatisch an, wenn sich der Standort des Gerätes weit genug ändert. Im Gegensatz dazu haben alle Map-Items mit einer Ortsmarke eine feste Position auf der Karte. Sie können diese Objekte nur über den Initializer initWithPlacemark: konfigurieren und einmal erzeugte Objekte danach nicht mehr verändern.

Für die Erzeugung einer Ortsmarke benötigen Sie eine Geokoordinate und ein Dictionary mit den Adressdaten. Da die Ortsmarke für das Dictionary ebenfalls die Schlüssel aus dem AddressBook-Framework verwendet, nutzt das Beispielprojekt die Methode address der Klasse Site, die Sie bereits kennengelernt haben. Zusätzlich zu den Adressdaten kann ein Map-Item eine URL und einen Namen speichern. Mit folgendem Code legen Sie beispielsweise ein Map-Item zu einer Baustelle an:

MKPlacemark *thePlacemark = [[MKPlacemark alloc]  
initWithCoordinate:theSite.coordinate
addressDictionary:theSite.address];
MKMapItem *theItem = [[MKMapItem alloc]
initWithPlacemark:thePlacemark];

theItem.name = theSite.name;

Listing 8.85 Erzeugung eines Map-Items zu einer Baustelle

Die Methode openInMapsWithLaunchOptions: der Klasse MKMapItem ermöglicht es Ihnen, diesen Eintrag in der Karten-App anzeigen zu lassen. Sie können für die Optionen einfach nil angeben; dann zeigt die Karten-App das Map-Item einfach nur an. Da jedoch bereits die SiteSchedule-App einen entsprechenden Eintrag auf ihrer Karte anzeigt, haben Sie damit noch nicht viel gewonnen. Durch die Optionen aus Tabelle 8.19 können Sie indes die Darstellung der Karten-App beeinflussen.

Tabelle 8.19 Aufrufoptionen für die Karten-App

Schlüssel (Wert bzw. Typ) Beschreibung

MKLaunchOptionsDirectionsModeKey
(MKLaunchOptionsDirectionsModeDriving
oder -Walking)

Stellt Routen zwischen den Map-Items dar. Wenn der Aufruf nur ein Element enthält, startet die Route beim aktuellen Standort.

MKLaunchOptionsMapTypeKey
(MKMapType)

Die Art der Kartendarstellung. Um diesen Wert in das Dictionary einfügen zu können, müssen Sie ihn in ein NSNumber-Objekt verpacken.

MKLaunchOptionsMapCenterKey
(MKCoordinate)

Legt den Mittelpunkt der Karte fest. Den Wert müssen Sie über die Klassenmethode valueWithMKCoordinate in ein NSValue-Objekt kapseln.

MKLaunchOptionsMapSpanKey
(MKCoordinateSpan)

Enthält die Größe der angezeigten Karte. Den Wert müssen Sie über die Klassenmethode valueWithMKCoordinateSpan in ein NSValue-Objekt kapseln.

MKLaunchOptionsShowsTrafficKey
(NSNumber)

Blendet für den Wert YES Verkehrsinformationen ein.

Sie brauchen in den Optionen natürlich nur die von Ihnen benötigten Einträge zu setzen; für die nicht gesetzten Werte verwendet die App automatisch sinnvolle Einstellungen. Die SiteSchedule-App öffnet beim Antippen des rechten Buttons in Abbildung 8.31 der Sprechblase den in Listing 8.85 erzeugten Eintrag folgendermaßen:

[theItem openInMapsWithLaunchOptions:@{
MKLaunchOptionsDirectionsModeKey :
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey : @YES }];

Listing 8.86 Anzeige eines Eintrags in der Karten-App

Die Karten-App zeigt also durch diese Optionen auch mögliche Routen vom aktuellen Standort zu der Baustelle und die verfügbaren Verkehrsinformationen an.

Mit der Klassenmethode openMapsWithItems:launchOptions: können Sie mehrere Map-Items in der Karten-App anzeigen lassen, die Sie im ersten Parameter in einem Array übergeben. Für die Optionen können Sie die gleichen Schlüssel-Wert-Paare wie bei der Methode openInMapsWithLaunchOptions: verwenden. Dabei dürfen Sie die Option MKLaunchOptionsDirectionsModeKey indes nur benutzen, wenn das Array höchstens zwei Einträge enthält. Die Karten-App zeigt bei genau zwei Map-Items mögliche Routen von dem ersten zu dem zweiten Map-Item an.

Wenn die Methoden openInMapsWithLaunchOptions: beziehungsweise openMapsWithItems:launchOptions: die Karten-App jeweils nicht öffnen konnten, liefern sie als Ergebnis NO.

Start der Maps-App über eine URL

Unter den iOS-Versionen vor 6 konnten Sie die Karten-App nur über eine URL öffnen, die einer offiziellen Google-Maps-URL entspricht. Dabei lautet die Basis-URL http://map.google.de/maps?. An diese Basis-URL müssen Sie noch die Parameter für die Konfiguration der Karte anhängen.

Tabelle 8.20 URL-Parameter für Google-Maps

Parameter Bemerkungen

q

Enthält einen Suchbegriff für eine Adresse, wie Sie ihn von der Google-Maps-Webseite kennen.

ll

Legt den Mittelpunkt der Karte in Geokoordinaten fest.

spn

Legt den Bereich der Karte um den Mittelpunkt fest.

t

Enthält die Art der Kartendarstellung. Mögliche Werte: roadmap, satellite, hybrid und terrain

z

der Vergrößerungsfaktor

saddr

Bei der Anzeige von Routen enthält dieser Parameter die Startadresse.

daddr

Bei der Anzeige von Routen enthält dieser Parameter die Zieladresse.

Geokoordinaten geben Sie in den Parametern mit Dezimalpunkt und durch ein Komma getrennt an. Wenn Sie die URL konstruiert haben, starten Sie damit die Karten-App, indem Sie die URL als Parameter an die Methode openURL: des Application-Singletons übergeben. Wenn Sie beispielsweise eine Karte mit dem Kölner Dom im Zentrum anzeigen möchten, können Sie das folgendermaßen machen:

NSURL *theURL = [NSURL URLWithString: 
@"http://maps.google.de/maps?q=50.941302,6.957189"];
UIApplication *theApplication =
[UIApplication sharedApplication];

[theApplication openURL:theURL];

Listing 8.87 Anzeigen eines Standortes in der Google-Karten-App

Wenn Sie eine Route anzeigen möchten, müssen Sie die Parameter saddr und daddr in der URL mit den Geokoordinaten des Start- und des Zielpunktes angeben.

Tipp

Wenn Sie die URL dynamisch erstellen möchten, sollten Sie die Parameterwerte mit der Kategoriemethode encodedStringForURLWithEncoding: aus Listing 8.9 maskieren.

Falls Ihre App sowohl iOS 5 als auch iOS 6 unterstützen soll, ist es sinnvoll, die Verfügbarkeit der Klasse MKMapItem zu überprüfen, um den richtigen Weg für die Anzeige der Karten-App herauszufinden. Für den Test nutzen Sie die Funktion NSClassFromString, die nil liefert, wenn die angegebene Klasse nicht existiert. Damit können Sie nun den fehlenden else-Teil für Listing 8.84 implementieren:

else if(NSClassFromString(@"MKMapItem") == nil) {
CLLocationCoordinate2D theCoordinate =
theSite.coordinate;
NSString *theQuery = [NSString
stringWithFormat:@"%f,%f",
theCoordinate.latitude, theCoordinate.longitude];
NSString *theString = [NSString
stringWithFormat:@"http://maps.google.de/maps?q=%@",
[theQuery encodedStringForURLWithEncoding:
NSUTF8StringEncoding]];
NSURL *theURL = [NSURL URLWithString:theString];
UIApplication *theApplication =
[UIApplication sharedApplication];

[theApplication openURL:theURL];
}
else {
MKPlacemark *thePlacemark = [[MKPlacemark alloc]
initWithCoordinate:theSite.coordinate
addressDictionary:theSite.address];
MKMapItem *theItem = [[MKMapItem alloc]
initWithPlacemark:thePlacemark];

theItem.name = theSite.name;
[theItem openInMapsWithLaunchOptions:@{
MKLaunchOptionsDirectionsModeKey :
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey : @YES }];
}

Listing 8.88 Anzeige einer Route in der Karten-App

Listing 8.88 verwendet unter iOS 5 eine URL und unter iOS 6 ein Map-Item zum Öffnen der Karten-App.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück




Copyright © Rheinwerk Verlag GmbH, Bonn 2014
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de


  Zum Katalog
Zum Katalog: Apps programmieren für iPhone und iPad






Apps programmieren für iPhone und iPad
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Apps programmieren für iPhone und iPad






Apps programmieren für iPhone und iPad


Zum Katalog: Einstieg in Objective-C 2.0 und Cocoa






Einstieg in Objective-C 2.0 und Cocoa


Zum Katalog: Spieleprogrammierung mit Android Studio






Spieleprogrammierung mit Android Studio


Zum Katalog: Android 5






Android 5


Zum Katalog: iPhone und iPad-Apps entwickeln






iPhone und iPad-Apps entwickeln


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo