Route-me: placing a new route on a map - ios

I have an app that uses Route-me with static maps (tiles stored in a sqlite database). The code below correctly adds a route to the map. However, I would like to have the app remove the route shown and add another route. In the code, the function gets a new set of route points (the variable pathNodes) in this line (the [route createRoute:whichRoute] method pulls the datapoints from the sqlite database - this works correctly):
pathNodes = [route createRoute:whichRoute];
Then I remove the existing layer in this code:
// remove the current layer, which holds the previous route
if (currentLayer != nil) {
[mapView.contents.overlay removeSublayer:currentLayer];
}
and add a new layer in this:
[mapView.contents.overlay addSublayer:(CALayer *)walkRoute.path];
For the first route created, this works perfectly. But when a new route is chosen, the existing layer gets removed and the new sublayer is added to the mapView, but is never shown.
It appears to me that this is just a matter of getting the mapView to redraw itself with the new sublayer, but I've tried everything i can think of or discover elsewhere, and nothing has worked.
How do I get the mapView to redraw itself. Or is there another problem that I'm not seeing?
All help will be greatly appreciated!
- (void) setRoute {
NSMutableArray *pathNodes;
int whichRoute = delegate.selectedRoute; // delegate.whichRoute will be an integer denoting which route the user has chosen
Route *route = [[Route alloc] init];// Route stores information about the route, and a way to create the path nodes from a sqlite database
pathNodes = [route createRoute:whichRoute];
CMRoute *walkRoute = [[CMRoute alloc] initWithNodes:pathNodes forMap:mapView];
// remove the current layer, which holds the previous route
if (currentLayer != nil) {
[mapView.contents.overlay removeSublayer:currentLayer];
}
[mapView.contents.overlay addSublayer:(CALayer *)walkRoute.path];
currentLayer = (CALayer *)walkRoute.path;
// set the map's center point, whkch is the startPointlat and long stored in route
CLLocationCoordinate2D demoCoordinate;
demoCoordinate.longitude = route.startPoint.longitude;
demoCoordinate.latitude = route.startPoint.latitude;
[mapView setNeedsDisplay];
[mapView moveToLatLong:demoCoordinate];
}

In case anyone is still looking at this...
I never got a RouteMe map to redraw a route when the route changed. However - and this is a big however - iOS 8 and 9 have all the necessary capabilities to do static maps and draw and re-draw routes. And it all works. I re-wrote the entire app in Swift using UIMapKit and it all works much better. Anyone thinking about using RouteMe - I'd recommend thinking twice and three times and four times about doing that. RouteMe is not being maintained and is just plain buggy in some key areas. (I looked at the source code once to see what the heck was going on and found comments that there was some legacy code in the class that no one could figure out why it was there, but if removed, broke the class.)
UIMapKit - that's the answer.

Related

organizing too many arrays Xcode objc

I am working on an app that is going to have over 50 arrays with over 100 items in each array. They are used when certain conditions apply. Is there any way to put these on different pages and import them as needed. Here is a sample of my code.
if([washington isKindOfClass:[MKPolygon class]]){
MKPolygon *polygons = (MKPolygon*) washington;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygons.points;
for (int p=0; p < polygons.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, TRUE)){
citiesArray10000 = [NSArray arrayWithObjects:
#"47.620499&-122.350876&187&Seattle Washington",
#"47.673554&-117.416595&1843&Spokane Washington",
#"47.252199&-122.459832&&Tacoma Washington",
#"45.637236&-122.596516&&Vancouver Washington",
#"47.597839&-122.156489&&Bellevue Washington",
#"47.385318&122.2169290&&Kent Washington",
#"48.003267&-122.174223&&Everett Washington",
#"47.476075&-122.192026&&Renton Washington",
#"47.308837&-122.336104&&Federal Way Washington",nil;
there are 50 states thus 50 if statements and there are going to be 6 or more arrays per state and as many as 100 to 200 entries in each array.
This makes for a very extensive view controller page with all this information. Is there to put each state's arrays on one page and somehow call them when needed. Sorry this is probably simple but I don't know how to do it.
Put the data in plist files stored in your app's bundle. Then you can load each plist file as needed. Don't hardcode that much data in your code. It takes forever to compile and it is hard to read your code.
You might want to write some sort of data model class that encapsulates the data. Then you view controller can create an instance of the data model specifying what data is needed. The data model class can take care of loading the correct data as needed.
you can use MVC architecture for your code. Keep only the code that changes the view that will be visible to user such as changing textfields and labels in viewController and write all other functions in different file and call those functions as needed. Like creating points and getting information can be done on other files as model to this view controller.
It looks like the best practice in this case is to use SQLlite or some other local database to maintain such data.

CoreData not returning updated values

I'm working with some existing code that interacts with CoreData. I made some changes that I later realized introduced a regression. I was able to isolate the lines of code that introduced the problem, but I cannot for the life of me understand why it's an issue at all.
The code involves reading articles and marking them as read. I didn't make any changes to the marking code and determined that still functions correctly. However, in another layer of the code that's getting the list of read articles, I made the following change:
//Old
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
[self retrieveReadArticles];
...
}
- (void)retrieveReadArticles {
userHistory = [UserHistory retrieveUserHistory]; //stored in iVar
self.readArticles = userHistory.readArticles;
}
The above works fine, and gives me an updated list of read articles.
//New
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
...
[self retrieveReadArticles];
...
}
- (void)retrieveReadArticles {
UserHistory* userHistory = [UserHistory retrieveUserHistory]; //local variable
self.readArticles = userHistory.readArticles;
}
This change in scope breaks the functionality, and causes the list of read articles to never update.
A colleague and I were speculating that the ivar allows the operation to complete fully, while the local variable must not be retained properly and goes out of scope before it can return updates. Can anyone point me toward a resource that explains this unexpected behavior?
It looks like the marking code may have been the problem after all. We were retrieving a dictionary of existing read articles, adding another entry to it, and saving the UserHistory object again. Changing that code to create a brand new dictionary with the existing read articles appears to solve the problem without needing to use ivar scope.

Unable to set CEMarker's collisionPriority

I'm trying to "mimic" the BusinessLayer functionality by creating a CEMarkerGroup for my own markers, then setting the following:
CEMarkerGroup *myGroup = [self.mapView markerGroupWithName:#"myMarkers"];
[myGroup setShouldTestForCollisions:YES];
And then, according to the Citymaps' current documentation, I try to set individual collisionPriority values to each like this:
[marker setCollisionPriority:25.0f]; //<-- ERROR!!, or
marker.collisionPriority = 25.0f; //<-- same ERROR
[myGroup addMarker:marker];
Error is: No visible #interface for 'CEMarker' declares the selector 'setCollisionPriority:'
As my goal is to approximate Citymaps' very slick behavior of avoiding marker overlaps, does anyone know of a workaround for this issue, or perhaps another approach altogether? Much thanks!
I am a developer at Citymaps. Thank you for your interest in our SDK!
Our documentation got a bit ahead of itself. Turns out, we never exposed the collisionPriority property. I've given myself a ticket to do so, and will let you know immediately when a new build is out containing this change.

Using offline map sources with Monotouch's Route-me binding

I'm trying to get route-me to show an offline map which is bundled or to be downloaded after app installation. I'm using route-me bindings sample project to get the work done just for now. I also use the mbtiles file from the original route-me repo's SampleMap project. I copy the file to project's root directory and set it's build action to BundleResource (that's what I thought would be appropriate). After that I changed to code to this :
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
RMDBMapSource dbSource = new RMDBMapSource ("Philadelphia.mbtiles");
MapView = new RMMapView(View.Frame, dbSource.Handle);
MapView.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
if (UIScreen.MainScreen.Scale > 1.0)
MapView.AdjustTilesForRetinaDisplay = true;
Add (MapView);
}
But no luck. App runs in the simulator but showing only a grey background nothing more. So I need someone to help me and tell me what I'm doing wrong. I need to get it done this week since next week is the deadline for project. So any help would be appreciated.
I haven't actually used offline tiles myself, but based on this thread it looks like you might need to put the RMDBMapSource into an instance of RMMapContents instead of directly into the MapView. So I'm thinking it would be something like this with Xamarin:
RMDBMapSource dbSource = new RMDBMapSource ("Philadelphia.mbtiles");
MapView = new RMMapView(View.Frame, new IntPtr());
RMMapContents contents = new RMMapContents (MapView.Handle, dbSource.Handle);
That assumes you have a wrapper binding for RMMapContents too which from the looks of it the bindings project does not have by default. You'd need to throw in a wrapper that at least defines the constructor.
This page looks like it provides similar code (in Obj-C) towards the bottom.

How to route between two addresses using the new iOS 6.0 maps?

I'm using the iOS 6.0 SDK and I would like to route between two different addresses (not latitude and longitude) with Apple's new iOS 6.0 maps. I would like to show the indications too.
How can I do this?
I looked into do doing this last week and did not figure out a way to do it. It appears that you can give a destination, and you can sort of give it more than just coordinates, but it always assumes your starting position is the current location. That is limiting when you may be planning a trip while you are not currently at the starting location. (But perhaps I am just not seeing how it is done and I hope someone can correct me if that is true.)
A while back I looked into routing options for iOS 6 and gathered the results here...
How would you providing routing for directions between points on a map? What are the missing pieces?
You still may not be able to open up Apple Maps with the exact routing that you want, but perhaps you can draw the route with overlays and annotations on your own instance MKMapView. That may be the best you can do for now.
Below is the code that I used to route to a location and provide at least a label for the destination instead of leaving it to only coordinates. I found that simply giving the destination a label with the full address details would not work, so I just provide that one value.
if (flag != DirectionsFlag_PublicTransit && itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
NSDictionary *address = #{ (NSString *)kABPersonAddressStreetKey : location.title };
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:location.coordinate addressDictionary:address];
MKMapItem *destinationMapItem = [[MKMapItem alloc] initWithPlacemark:destinationPlacemark];
if (flag == DirectionsFlag_Driving) {
[destinationMapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving}];
}
else if (flag == DirectionsFlag_Walking) {
[destinationMapItem openInMapsWithLaunchOptions:#{MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeWalking}];
}
}
This code specifically does not handle Public Transit directions since Apple Maps does not do that. I instead have it open up Google Maps with the URL that I was using previously which now opens up Safari for those directions. The flag is an enum value of Driving, Walking or Public Transit. The location is a model which contains various details including title and coordinates.

Resources