New to monotouch aka xamarin ios. Trying to get a robust mapkit working that can take a number of pins. Experimenting with a basic example that I've cobbled together from a variety of sources that I could find.
Getting a sporadic SIGSEGV error. Seems like some sort of memory error when the pins are clicked to show an alert box which sometimes works and sometimes doesnt.
I'm not sure where I'm going wrong. Is this along the right lines? Here's the code
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.MapKit;
using MonoTouch.CoreLocation;
using System.Collections.Generic;
namespace singleview
{
public partial class singleviewViewController : UIViewController
{
public singleviewViewController () : base ("singleviewViewController", null)
{
}
private LocationService locationService;
private MKMapView mapView;
List<BasicMapAnnotation> pins = new List<BasicMapAnnotation>();
public override void ViewDidLoad()
{
base.ViewDidLoad();
// example of a series of map points
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.766995, -122.419580), "h", "sub1", "id1"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.776880, -122.418485), "i", "sub2", "id2"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.786775, -122.417390), "j", "sub3", "id3"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.796685, -122.416283), "k", "sub4", "id4"));
var currentLocation = new LocationService().GetCurrentLocation();
var visibleRegion = BuildVisibleRegion(currentLocation);
mapView = BuildMapView(true);
mapView.SetRegion(visibleRegion, true);
this.View.AddSubview(mapView);
// i have a vague idea that this delegate helps to redraw pins as user moves around screen
mapView.Delegate = new MapViewDelegate();
// this pin sometimes has a working callout that activates an alert and sometimes doesnt
var testAnnotationX = new BasicMapAnnotation (new CLLocationCoordinate2D(37.786999,-122.500222),
"made in viewdidload", "outside", "id5");
mapView.AddAnnotation(testAnnotationX);
// this pin collection also sometimes works but most often not
mapView.AddAnnotations(pins.ToArray());
}
private MKMapView BuildMapView(bool showUserLocation)
{
var view = new MKMapView()
{
ShowsUserLocation = showUserLocation,
};
view.Delegate = new MapViewDelegate();
var testAnnotationY = new BasicMapAnnotation (new CLLocationCoordinate2D(37.800000, -122.450777),
"made in buildmapview", "inside", "id6");
view.AddAnnotation(testAnnotationY);
view.SizeToFit();
view.Frame = new RectangleF(0, 0, this.View.Frame.Width, this.View.Frame.Height);
return view;
}
protected class MapViewDelegate : MKMapViewDelegate {
protected string annotationIdentifier = "BasicAnnotation";
UIButton detailButton; // avoid GC
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
{
if (annotation is MKUserLocation) return null; //ignore user marker
annotationIdentifier = (annotation as BasicMapAnnotation).Id;
// try and dequeue the annotation view
MKAnnotationView annotationView = mapView.DequeueReusableAnnotation(annotationIdentifier);
// if we couldn't dequeue one, create a new one
if (annotationView == null)
{
annotationView = new MKPinAnnotationView(annotation, annotationIdentifier);
//annotationView.RightCalloutAccessoryView = new UIButton(UIButtonType.DetailDisclosure); //- not required as its at bottom??
// configure our annotation view properties
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
// you can add an accessory view; in this case, a button on the right and an image on the left
detailButton = UIButton.FromType(UIButtonType.DetailDisclosure);
detailButton.TouchUpInside += (s, e) => {
Console.WriteLine ("Clicked");
new UIAlertView("Annotation Clicked", "You clicked on " +
(annotation as MKAnnotation).Coordinate.Latitude.ToString() + ", " +
(annotation as MKAnnotation).Coordinate.Longitude.ToString() , null, "OK", null).Show();
};
annotationView.RightCalloutAccessoryView = detailButton;
}
else // if we did dequeue one for reuse, assign the annotation to it
annotationView.Annotation = annotation;
/*
// configure our annotation view properties
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
*/
// fix and uncomment
//annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromBundle("29_icon.png"));
return annotationView;
}
// as an optimization, you should override this method to add or remove annotations as the
// map zooms in or out.
public override void RegionChanged (MKMapView mapView, bool animated) {}
}
private MKCoordinateRegion BuildVisibleRegion(CLLocationCoordinate2D currentLocation)
{
var span = new MKCoordinateSpan(0.2,0.2);
var region = new MKCoordinateRegion(currentLocation,span);
return region;
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
}
public class BasicMapAnnotation : MKAnnotation{
public override CLLocationCoordinate2D Coordinate {get;set;}
string title, subtitle;
public override string Title { get{ return title; }}
public override string Subtitle { get{ return subtitle; }}
public string Id {get ;set;}
public BasicMapAnnotation (CLLocationCoordinate2D coordinate, string title, string subtitle, string id) {
this.Coordinate = coordinate;
this.title = title;
this.subtitle = subtitle;
this.Id = id;
}
}
public class LocationService
{
private CLLocationManager locationManager;
public LocationService()
{
locationManager = new CLLocationManager();
}
public CLLocationCoordinate2D GetCurrentLocation()
{
//dirty for now just to get some info.
locationManager.StartUpdatingLocation();
while(locationManager.Location == null);
locationManager.StopUpdatingLocation();
//return new CLLocationCoordinate2D ( 37.786995, -122.419280);
return locationManager.Location.Coordinate;
}
}
}
Error:
Stacktrace:
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38 at singleview.Application.Main (string[]) [0x00000] in .../singleview/Main.cs:17 at (wrapper runtime-invoke) .runtime_invoke_void_object (object,intptr,intptr,intptr)
Native stacktrace:
0 singleview 0x00091eac mono_handle_native_sigsegv + 284
1 singleview 0x00005788 mono_sigsegv_signal_handler + 248
2 libsystem_c.dylib 0x938658cb _sigtramp + 43
3 ??? 0xffffffff 0x0 + 4294967295
4 UIKit 0x0274f258 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
5 UIKit 0x02810021 -[UIControl sendAction:to:forEvent:] + 66
6 UIKit 0x0281057f -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 578
7 UIKit 0x0280f6e8 -[UIControl touchesEnded:withEvent:] + 546
8 UIKit 0x0277ecef -[UIWindow _sendTouchesForEvent:] + 846
9 UIKit 0x0277ef02 -[UIWindow sendEvent:] + 273
10 UIKit 0x0275cd4a -[UIApplication sendEvent:] + 436
11 UIKit 0x0274e698 _UIApplicationHandleEvent + 9874
12 GraphicsServices 0x04d40df9 _PurpleEventCallback + 339
13 GraphicsServices 0x04d40ad0 PurpleEventCallback + 46
14 CoreFoundation 0x012bfbf5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
15 CoreFoundation 0x012bf962 __CFRunLoopDoSource1 + 146
16 CoreFoundation 0x012f0bb6 __CFRunLoopRun + 2118
17 CoreFoundation 0x012eff44 CFRunLoopRunSpecific + 276
18 CoreFoundation 0x012efe1b CFRunLoopRunInMode + 123
19 GraphicsServices 0x04d3f7e3 GSEventRunModal + 88
20 GraphicsServices 0x04d3f668 GSEventRun + 104
21 UIKit 0x0274bffc UIApplicationMain + 1211
22 ??? 0x0f4d71ad 0x0 + 256733613
23 ??? 0x0f4d4e40 0x0 + 256724544
24 ??? 0x0f4d4a48 0x0 + 256723528
25 ??? 0x0f4d4b9e 0x0 + 256723870
26 singleview 0x00009b52 mono_jit_runtime_invoke + 722
27 singleview 0x0016d02e mono_runtime_invoke + 126
28 singleview 0x00171224 mono_runtime_exec_main + 420
29 singleview 0x00176615 mono_runtime_run_main + 725
30 singleview 0x000671e5 mono_jit_exec + 149
31 singleview 0x00204fd4 main + 1988
32 singleview 0x00002b75 start + 53
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
Looks like the good old GC Error.
Take a look at the Monotouch-Samples App exactly this Class and Line:
https://github.com/xamarin/monotouch-samples/blob/master/MapCallouts/MainViewController.cs#L108
You need to store all the Pinviews within some Collection, so the Garbage Collection doesn't try to collect them.