Frage zu MapKit und Annotations

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Frage zu MapKit und Annotations

    Hallo,

    ich habe eine Frage zu MapKit. Ich habe diesem Thema eine kleine DEMO-App angehangen, damit ihr gleich wisst worum es geht.

    Ich habe eine App zum Testen gebaut, in der ein MapView angezeigt wird. Mit wenigen Buttons kann man Art der Karte einstellen, Pins setzen und auf Deutschland zoomen.

    Mein Anspruch wäre nun noch folgendes: Ich setze zwei Pins und möchte auch beide mit einem PNG ausstatten. Wenn ich nur einen Pin anpassen möchte funktioniert es:

    Quellcode

    1. if ([annotation isKindOfClass:[MapAnnotation class]]) {
    2. MKAnnotationView* customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
    3. customAnnotationView.image = [UIImage imageNamed:@"pin1.png"];
    4. customAnnotationView.canShowCallout = YES;
    5. UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pin1.png"]];
    6. customAnnotationView.leftCalloutAccessoryView = leftIconView;
    7. UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    8. [rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
    9. customAnnotationView.rightCalloutAccessoryView = rightButton;
    10. return customAnnotationView;
    11. }
    Alles anzeigen


    Wenn ich nun aber beide Pins unterschiedlich anpassen möchte stürzt die App ohne Log-Eintrag ab:

    Quellcode

    1. if ([annotation isKindOfClass:[MapAnnotation class]]) {
    2. MKAnnotationView* customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
    3. customAnnotationView.image = [UIImage imageNamed:@"pin1.png"];
    4. customAnnotationView.canShowCallout = YES;
    5. UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pin1.png"]];
    6. customAnnotationView.leftCalloutAccessoryView = leftIconView;
    7. UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    8. [rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
    9. customAnnotationView.rightCalloutAccessoryView = rightButton;
    10. return customAnnotationView;
    11. }
    12. if ([annotation isKindOfClass:[MapAnnotation2 class]]) {
    13. MKAnnotationView* customAnnotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
    14. customAnnotationView.image = [UIImage imageNamed:@"pin2.png"];
    15. customAnnotationView.canShowCallout = YES;
    16. UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pin2.png"]];
    17. customAnnotationView.leftCalloutAccessoryView = leftIconView;
    18. UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    19. [rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
    20. customAnnotationView.rightCalloutAccessoryView = rightButton;
    21. return customAnnotationView;
    22. }
    Alles anzeigen


    Daher nun meine Frage. Warum passiert dies? Was mache ich noch falsch?

    Weiterhin beschäftigt mich noch folgendes:
    - Warum überschreibt es beim Setzen von Pins immer den blauen Punkt von UserLocation? Kann man das verhindern?
    - Wie kann ich den Klick auf den Button im PopUp (annotationViewClick) differenziert nutzen, also mal dieses Ereignis, mal jenes? Da habe ich noch keine Idee wie ich das abfragen soll, welcher Pin das gerade ist. Oder an welcher Stelle kann ich eine ID mitgeben oder ähnliches?

    Vielen Dank schonmal.

    Gruß
    Daniel
  • Du kannst doch der Annotation gleich ein property mitgeben, in dem du den Selector setzt, der dann beim TouchUp ausgeführt wird. So kannst du jeder Annotation einen anderen Selektor geben. Ansonsten, wenn das nicht zu unübersichtlich bleibt, dann eben eine id setzen und dann den guten alten switch(){case:...} nutzen, um je nach id was anderes zu tun.
  • ssb schrieb:

    Du kannst doch der Annotation gleich ein property mitgeben, in dem du den Selector setzt, der dann beim TouchUp ausgeführt wird. So kannst du jeder Annotation einen anderen Selektor geben.

    Ich möchte aber bei jedem Klick in die gleiche Methode gehen. Und dies mache ich derzeit so:

    Quellcode

    1. [rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];

    Innerhalb von - (IBAction) annotationViewClick:(id) sender { ... } möchte ich dann je nach Pin ein DetailView ausgeben. Dazu benötige ich aber eine Info welcher Pin das nun war. Und den bekomme ich doch im Selector nicht mehr unter oder?

    ssb schrieb:

    Ansonsten, wenn das nicht zu unübersichtlich bleibt, dann eben eine id setzen und dann den guten alten switch(){case:...} nutzen, um je nach id was anderes zu tun.

    Wie kann ich einer Annotation eine ID mitgeben und die dann wieder auslesen? Derzeit erstelle ich den Pin so:

    Quellcode

    1. [mapView setDelegate:self];
    2. [mapView removeAnnotations:mapView.annotations]; // Alle Pins entfernen
    3. CLLocationCoordinate2D coordinate;
    4. // Pin 1
    5. coordinate.latitude = 51.151786;
    6. coordinate.longitude = 10.415039;
    7. mapAnnotation = [[MapAnnotation alloc] initWithCoordinate:coordinate];
    8. mapAnnotation.title = [NSString stringWithFormat:@"Titel 1"];
    9. mapAnnotation.subtitle = [NSString stringWithFormat:@"Subtitel 1"];
    10. [mapView addAnnotation:mapAnnotation];
    11. [mapAnnotation release];
    Alles anzeigen


    Vielen Dank.

    Daniel :)
  • longW schrieb:

    _Daniel_ schrieb:

    if ([annotation isKindOfClass:[MapAnnotation2 class]]) {

    a) Wie und wo ist Deine Klasse "MapAnnotation2" definiert?
    b) Über Klassen zu unterscheiden halte ich für den denkbar ungeeignetesten Weg.

    Hallo,

    mein Projekt hängt als Datei an (erster Beitrag). Dort kann man dann sehen, dass ich einfach ein Objekt erstellt habe. Den Weg über Klassen habe ich übrigens aus dem original Beispiel von Apple namens "Map Callouts" entnommen. Ich dachte das sei ein gängiger Weg.

    MapAnnotation2.h:

    Quellcode

    1. #import <MapKit/MapKit.h>
    2. @interface MapAnnotation2 : NSObject <MKAnnotation> {
    3. CLLocationCoordinate2D coordinate;
    4. NSString *subtitle;
    5. NSString *title;
    6. }
    7. @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
    8. @property (nonatomic,retain) NSString *subtitle;
    9. @property (nonatomic,retain) NSString *title;
    10. -(id)initWithCoordinate:(CLLocationCoordinate2D) coord;
    11. @end
    Alles anzeigen


    MapAnnotation2.m:

    Quellcode

    1. #import "MapAnnotation2.h"
    2. @implementation MapAnnotation2
    3. @synthesize coordinate, title, subtitle;
    4. -(id)initWithCoordinate:(CLLocationCoordinate2D) coord {
    5. coordinate = coord;
    6. return self;
    7. }
    8. #pragma mark -
    9. #pragma mark Memory management
    10. - (void)dealloc {
    11. [title release];
    12. [subtitle release];
    13. [super dealloc];
    14. }
    15. @end
    Alles anzeigen


    Wie sieht denn die Alternative aus?

    Gruß
    Daniel
  • _Daniel_ schrieb:

    coordinate = coord;

    Diese Zeile beim Initialisieren verstehe ich nicht. Das soll anscheinend ein Gleichheitszeichen sein.
    Deine Klasse verwendest Du faktisch nicht.
    Die Idee des Protokolls ist es doch gerade, Klassen zu kreieren, die Titel und Untertitel anbieten.
    I would be embarrassed if they did not spy on me.
  • longW schrieb:

    _Daniel_ schrieb:

    coordinate = coord;

    Diese Zeile beim Initialisieren verstehe ich nicht. Das soll anscheinend ein Gleichheitszeichen sein.
    Deine Klasse verwendest Du faktisch nicht.
    Die Idee des Protokolls ist es doch gerade, Klassen zu kreieren, die Titel und Untertitel anbieten.

    Also nun verwirrst du mich. Ich habe den Code aus dem Buch "iPhone-Apps entwickeln" entnommen. Und bisher funktioniert er ganz gut. Ich habe bisher nur ein Problem mit dem Austauschen des PIN-Bildes. Und das hängt doch damit jetzt nicht zusammen oder? Ich tue ja genau das was das Protokoll erwartet.

    Wenn du dir die App die ich am ersten Beitrag angehangen habe mal anschaust, kannst du sehen das alles funktioniert (bis auf das setzen des zweiten PIN-Bildes).

    Trotzdem vielen Dank.

    Gruß
    Daniel
  • Ich möchte weder bezweifeln, dass es nicht funktioniert, noch, dass Deine Vorlage unbrauchbar ist.
    Was ich sehe, ist eine Unterscheidung anhand nur der Klassen, ohne die Eigenschaften der Instanzen zu nutzen.
    Du kannst für jede Instanz eine Klasse erzeugen, und es wird auch funktionieren können, aber es ist nicht Sinn der Sache.

    Fülle mal Titel und Untertitel in den Klassen, die das Protokoll nutzen. Sie werden vom MapKit genutzt.
    I would be embarrassed if they did not spy on me.
  • _Daniel_ schrieb:

    longW schrieb:

    _Daniel_ schrieb:

    coordinate = coord;

    Diese Zeile beim Initialisieren verstehe ich nicht. Das soll anscheinend ein Gleichheitszeichen sein.
    Deine Klasse verwendest Du faktisch nicht.
    Die Idee des Protokolls ist es doch gerade, Klassen zu kreieren, die Titel und Untertitel anbieten.

    Also nun verwirrst du mich. Ich habe den Code aus dem Buch "iPhone-Apps entwickeln" entnommen. Und bisher funktioniert er ganz gut. Ich habe bisher nur ein Problem mit dem Austauschen des PIN-Bildes. Und das hängt doch damit jetzt nicht zusammen oder? Ich tue ja genau das was das Protokoll erwartet.

    Wenn du dir die App die ich am ersten Beitrag angehangen habe mal anschaust, kannst du sehen das alles funktioniert (bis auf das setzen des zweiten PIN-Bildes).

    Trotzdem vielen Dank.

    Gruß
    Daniel


    Jetzt habe ich mir doch den Remmel angeschaut.
    Erstmal:
    Warnungen sind da, um beachtet zu werden.
    Du erhälst:
    …MapViewTestViewController.m:98: warning: control reaches end of non-void function

    Dann schaut man nach:
    aus der Doku:
    Return Value
    The annotation view to display for the specified annotation or nil if you want to display a standard annotation view.


    und dann steht in der letzten Zeile ain

    Quellcode

    1. - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    2. return nil;}


    Wenn Du das wirklich so aus Deinem Buch hast, würde ich versuchen, es umzutauschen.
    Oder gleich in die Tonne.
    I would be embarrassed if they did not spy on me.
  • Ausnahmsweise

    _Daniel_ schrieb:

    longW schrieb:

    _Daniel_ schrieb:

    coordinate = coord;


    Wenn du dir die App die ich am ersten Beitrag angehangen habe mal anschaust, kannst du sehen das alles funktioniert (bis auf das setzen des zweiten PIN-Bildes).

    Trotzdem vielen Dank.

    Gruß
    Daniel




    Das sollte so erstmal funktionieren.
    Die Unterscheidung geht jetzt über den Titel.
    I would be embarrassed if they did not spy on me.
  • longW schrieb:



    Jetzt habe ich mir doch den Remmel angeschaut.
    Erstmal:
    Warnungen sind da, um beachtet zu werden.
    Du erhälst:
    …MapViewTestViewController.m:98: warning: control reaches end of non-void function

    Dann schaut man nach:
    aus der Doku:
    Return Value
    The annotation view to display for the specified annotation or nil if you want to display a standard annotation view.


    und dann steht in der letzten Zeile ain

    Quellcode

    1. - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    2. return nil;}


    Wenn Du das wirklich so aus Deinem Buch hast, würde ich versuchen, es umzutauschen.
    Oder gleich in die Tonne.
    Ups ... also erst einmal vielen Dank für deine Geduld. Das war dann wohl der Fehler. Peinlich. Darauf hätte man wirklich kommen können. Gebe ich gern zu. Ich hatte in der Vergangenheit schon öfters mal diesen Fehler an anderen Stelle, doch zum Absturz hat er nie geführt. Daher dachte ich mir, kann man sich später drum kümmern. Erstmal den Absturz in den Griff bekommen. Aber nix war. Daher vielen Dank für deine Mühe. Und ich sehe auch ein, dass du bei so einem Ding mit mir schimpfst ;)

    Jetzt muss ich es nur noch schaffen, eine ID oder so jedem Pin mitzugeben, damit ich dann im DetailView was draus machen kann.


    Lieben Gruß
    Daniel
  • Quellcode

    1. - (IBAction) annotationViewClick:(id) sender
    2. {
    3. UIAlertView *alert = [[UIAlertView alloc]
    4. initWithTitle:@"Geklickt!"
    5. message:nil
    6. delegate:nil
    7. cancelButtonTitle:nil
    8. otherButtonTitles:@"OK", nil];
    9. [alert show];
    10. [alert release];
    11. }
    Alles anzeigen



    "release" von alert nicht vergessen !
  • _Daniel_ schrieb:

    Jetzt muss ich es nur noch schaffen, eine ID oder so jedem Pin mitzugeben, damit ich dann im DetailView was draus machen kann.

    Da hast Du freie Auswahl: Titel oder Untertitel als 'key', oder Deinen Buttons 'tags' mitgeben, usw.
    Du hast aber gemerkt, dass nur noch eine Klasse da ist, und auch keine Instanzvariablen für die Annotationen.
    Dafur gibt es keinen Grund, solange sie im MapView vorgehalten sind.
    I would be embarrassed if they did not spy on me.
  • longW schrieb:

    _Daniel_ schrieb:

    Jetzt muss ich es nur noch schaffen, eine ID oder so jedem Pin mitzugeben, damit ich dann im DetailView was draus machen kann.

    Da hast Du freie Auswahl: Titel oder Untertitel als 'key', oder Deinen Buttons 'tags' mitgeben, usw.
    Du hast aber gemerkt, dass nur noch eine Klasse da ist, und auch keine Instanzvariablen für die Annotationen.
    Dafur gibt es keinen Grund, solange sie im MapView vorgehalten sind.
    Hi,

    ich hatte deinen Beitrag mit dem Anhang erst bemerkt, als ich meinen schon geschrieben hatte. Ich werde mir deinen Anhang nun mal ganz genau anschauen und mich dann wieder melden.

    Vielen Dank schonmal :)

    Gruß
    Daniel
  • Hi,

    vielen Dank fürs "verschönern" meines Codes ;) Da bin ich dir sehr dankbar für.

    longW schrieb:

    Du hast aber gemerkt, dass nur noch eine Klasse da ist, und auch keine Instanzvariablen für die Annotationen.
    Dafur gibt es keinen Grund, solange sie im MapView vorgehalten sind.

    Ja das habe ich bemerkt. Das war aber die einzige Art, wie ich unterscheiden kann, dass ein Pin grün oder blau sein muss. Du gehst nun nach dem Title. Interessant zu wissen, dass man das auch machen kann. Nur mir würde das an der Stelle nix bringen, da die Info für grün oder blau nicht im Titel steckt. Die müsste ich nun anders kommunizieren. Daher hatte ich zwei Klassen gewählt. Wie würdest du das nun machen, ohne den Title zu nutzen? Kann man "mapAnnotation" nicht einen weiteren Wert außer die Koordinaten, Title und Subtitle mitgeben? Das wäre interessant, denn dann würde ich noch die Info grün oder blau sowie eine ID mitgeben. Und schon hätte ich alles für die Weiterverarbeitung.

    longW schrieb:

    Da hast Du freie Auswahl: Titel oder Untertitel als 'key', oder Deinen Buttons 'tags' mitgeben, usw.


    Tags an den Buttons würde ich gern nutzen, aber wie bekomme ich die in diese Methode rein? Wenn das was ich oben beschrieben habe funktioniert, dann würde ich es so machen. Aber bisher bin ich daran gescheitert. Wie gesagt, mein Problem ist das "weiterschleppen" der jeweiligen Infos. Daran arbeite ich derzeit.

    Hast du da noch einen winzigen Tipp auf Lager?

    Daniel
  • _Daniel_ schrieb:

    Hi,

    vielen Dank fürs "verschönern" meines Codes ;) Da bin ich dir sehr dankbar für.

    Das war ja nur Wegschmeißen, eine ganze Klasse, und die Hälfte von der Methode im 'delegate'.



    Tags an den Buttons würde ich gern nutzen, aber wie bekomme ich die in diese Methode rein? Wenn das was ich oben beschrieben habe funktioniert, dann würde ich es so machen. Aber bisher bin ich daran gescheitert. Wie gesagt, mein Problem ist das "weiterschleppen" der jeweiligen Infos. Daran arbeite ich derzeit.

    Hast du da noch einen winzigen Tipp auf Lager?

    Daniel

    Brauchst Du das wirklich?

    Du solltest Dich ernsthaft in das spezifische Denken von OOP in Cocoa einarbeiten.
    Deine Landkarte liefert doch schon ein Objekt, das von Deiner eigenen Klasse bestimmt ist, und nur dem Protokoll gehorchen muss.
    Das ist doch gerade das Tolle daran, wenn auch etwas trickreich.

    Also: Du willst ein Liedchen? Die Information ist in Deiner Klasse als Instanzvariable gespeichert, es geht, das weisst Du schon.
    Du rufst einfach Dein Objekt auf, so wie es in die 'delegate'-Methode herein kommt: Spiel mein Lied, und es wird das richtige Lied spielen.
    Vorsichtshalber kannst Du mit '-respondsToSelector' kontrollieren, ob es klappt.
    I would be embarrassed if they did not spy on me.
  • longW schrieb:

    Du solltest Dich ernsthaft in das spezifische Denken von OOP in Cocoa einarbeiten.
    Deine Landkarte liefert doch schon ein Objekt, das von Deiner eigenen Klasse bestimmt ist, und nur dem Protokoll gehorchen muss.
    Das ist doch gerade das Tolle daran, wenn auch etwas trickreich.

    Also: Du willst ein Liedchen? Die Information ist in Deiner Klasse als Instanzvariable gespeichert, es geht, das weisst Du schon.
    Du rufst einfach Dein Objekt auf, so wie es in die 'delegate'-Methode herein kommt: Spiel mein Lied, und es wird das richtige Lied spielen.
    Vorsichtshalber kannst Du mit '-respondsToSelector' kontrollieren, ob es klappt.

    Also ich bin dir sehr dankbar das du mir hilfst, aber scheinbar spreche ich deine Sprache nicht. Ich bin Gelegenheitsprogrammierer (Hobby) und muss mir alles hart erarbeiten. Dabei kann ich immer nur das was ich auch brauche. Das macht es sehr schwer neue Aufgaben zu bewältigen. Daher stelle ich mich auch gerade so an hier. Es ist eben nicht leicht mit diesem Thema voran zu kommen. Daher nun die Bitte: Kannst du das nochmal übersetzen?

    Ich habe schon versucht, meiner Klasse (nennt man das nicht auch Objekt?) neben den Koordinaten, Titel und Subtitle noch eine "art" als Instanzvariable hinzuzufügen. Doch leider wird das dann nicht zur Annotation hinzugefügt. So komme ich also nicht weiter.

    Was meinst du mit "Die Information ist in Deiner Klasse als Instanzvariable gespeichert, es geht, das weisst Du schon."?

    Kann ich dir irgendwas anbieten? Ein Bierchen oder so? ;) Ich stehe ja schon tief in deiner Schuld.

    Daniel
  • Ich hatte es schon vermutet: Verschaffe Dir Grundlagen, es lohnt sich.
    Mapkit, so schön es ist, ist dabei nicht gerade das Beste für Anfänger.

    Und wenn Du wirklich weisst, was Klassen, Instanzen, Instanzvariablen, Methoden usw. sind, musst Du auch gar nicht mehr so hart daran arbeiten.
    I would be embarrassed if they did not spy on me.