Performance issues with MapKit on iOS6 - ios

After updating to iOS 6 I have noticed sever performance decreases when panning or zooming a MKMapView with multiple overlays. An app I created has approximately 600 polygon overlays of various colours, and ran lag-free (even on older iOS devices) on iOS 5, now runs extremely laggily (when zooming & panning) on iOS 6, even on the latest devices.
My hunch is that this is due to the fact the device has to actually dynamically create the map (since its vector based) rather than just display tiles onscreen.
Has anyone got any ideas to reduce the lag experienced when panning or zooming the map?
Some extra info, this low frame rate also occurs whilst zooming or panning areas where the overlays are not displayed on screen at all, so it is not to do with the creation of the overlays as they come onscreen.

You can try combining all of your overlays into a single one. This can dramatically boost performance.
The idea is to create an overlay with a bounding box that encompasses all of your polygons. This way your mapView: viewForOverlay will always be called. Create a property for your overlay that holds all of your polygons. Then in the drawMapRect: method of your overlay view, test all of your polygons for intersection with mapRect and draw them if necessary. This is important since you don't want to be drawing polygons that are off screen.
This strategy is based on Apple's own MapKit example projects. Check out HazardMap for an example of drawing several objects in a single MKOverlayView and check out BreadCrumb for an example of how to efficiently test polygons for intersection with your current mapRect in the drawMapRect method

I have a minimalistic MapKit tech demo and it's lagging noticeably as I run it on an iPad 3 with iOS6. Profiling reveals that it's CPU bound, but only 0.2% is from my own code. The big culprits in my case are rendering roads, followed by rendering labels - both done by MapKit. I am showing downtown San Francisco at a 5KM scale, so there are a lot of roads and labels to render.
So the moral of the story is: iOS6 maps are SLOW. Can't tell you how this compares to iOS5 or to an iPad 2, though. But it's lagging, and I am barely doing any work of my own at all.
P.S:
Open Instruments and use the Time Profiler. Make a recording + drill down to find your culprits. Then check 'hide system libraries' to find out how much of the lag is your responsibility vs MapKit's. Then optimize only as needed.

Related

MKMapView renders map at very low quality

I'm using MKMapView to display a map on my iOS app. I've simulated my location to London for the sake of example as I know it has high quality aerial imagery.
Here is a picture from Apple's own Maps app. No problems, super quality:
Here is the same place from my app at the approximately same zoom level:
It looks like it's zoomed out, cropped and zoomed into that region as satellite image is from a more "zoomed out" zoom level. At that level, all the labels disappear too (in Maps), but I've got the labels. I've got multiple instances of MKMapView and the problem is present on all of them. I don't have any special filters, scaling, or anything that would affect the rendering of the maps. In other words, the view instances themselves aren't "zoomed in" in any way. What is exactly going on and how can I make MKMapView render the map at the quality where Maps renders it?
If you are using MKMapTypeSatellite type map, consider that this type has been abandoned by Apple.
Try using MKMapTypeSatelliteFlyover or MKMapTypeHybridFlyover for a better quality.

SpriteKit using 95-100% CPU when running game with large tilemap (JSTileMap)

My project runs at 55-60FPS on an iPhone 6 but anything older is completely unplayable because something is eating CPU.
I think the issue is related to the number of tiles and layers on my map (64x256 with 4 layers) and Instruments shows "SKCRenderer:preprocessSpriteImp(..." taking 5198ms (23.2%) running time.
Does JSTileMap load every single tile's image (visible or not) at once? This post from RW indicates that is the case and that it could be worked around for large performance boosts:
http://www.raywenderlich.com/forums/viewtopic.php?f=29&t=9479
In another performance note - Sprite Kit checks all it's nodes and
decides which ones it needs to display each frame. If you have a big
tile map, this can be a big performance hit. JSTileMap loads all the
nodes (SKSpriteNode for each tile) when it loads the tile map. So, I
was also seeing performance issues in the Sprite Kit version with my
maps (which are 500 x 40 tiles). I added a check to my version of
JSTileMap that's included in the kit that marks the hidden property of
each tile, then intelligently unhides and hides only the tiles that
enter/exit the screen space. That increased performance on these
larger maps significantly.
Unfortunately that post does not go into detail regarding the steps taken to remedy this.
My first thought was to (I'm a beginner, please be gentle) create an array of nodes by looping through each point and checking for a tile on the specific layer. From there I'd work on adding/removing them based on distance from the player.
This didn't work, because the process of adding nodes to an array simply caused the app to hang forever on larger maps.
Could someone lend a hand? I'd love to work with larger/more complicated tilemaps but this performance issue is destroying my brain.
Thanks for reading!
UPDATE: Big thanks to SKAToolKit: https://github.com/SpriteKitAlliance/SKAToolKit
Their culling feature solved my problem and I'm now running even larger maps at less than 35% CPU.
JSTileMap has some issues handling larger maps but you do have a couple of options to consider:
Break your large map into several smaller pieces and load each new piece as required.
Only load those objects which are in the player's vicinity.
Only load those tiles which are in the player's vicinity.
I personally found it impossible to accomplish #3 with JSTileMap as I could not locate an array holding the map tiles. I solved this issue by using the SKAToolKit which provides easy access to map tile arrays. It is an excellent resource for parsing maps created in Tiled.

Efficient way to draw many shapes on UIScrollView, scrollable and zoomable

I’m working on various iOS apps and I need an interface with the following capabilities:
I have a scrollview (covering most of the screen) which is scrollable both directions
This scrollable view contains a lot of rectangles. These rectangles are intractable. User can modify them, move them around, create and delete. So ideally they would be all CALayers or UIViews.
The problem is because there could be 100s or 1000s of those displayed at once, CALayers or UIViews may not be very efficient.
The scrollview could be 10-20 times bigger than the screen size itself. And fully covered with these shapes. So when the user scrolls it shouldn’t see any flickers or shapes appearing after the scrolling is done. e.g. If I use CATiledLayer and user scrolls, you can see things drawn after scrolling is done.
Smooth zooming. Zooming out is particularly challenging, because the shapes would need to be drawn on parts of the view which are going to become visible. Also, ideally I’d rather not use something like CGAffineTransform to perform scaling, I like to have a pixel accurate scaling.
I’ve tried various things, but I can’t seem to be able to get decent frame rates even on iPhone 6. Even tried drawing every frame, but it’s too expensive Core Graphics to handle it. Is there code examples someone trying to do a similar thing or an open source library? I’m trying not to use OpenGL, I feel like it’s an overkill, but I will try it if I have to. FYI, I have no experience in OpenGL yet.
Procreate for iPad does what I’m trying to do perfectly, it’s super responsive and zooming is pixel accurate. I know they use OpenGL and I’m not making drawing apps. The reason I mention it is because it shows what I’m trying to do is possible.
I think you need to move from UIKit to some 2d or 3d engines:
Cocos2D
Sparrow
Unity
OOlong

MapKit Overlays consuming massive CPU resources

I'm overlaying the contents of a third-party shapefile. Some of the polygons consist of 138,000 points, most of them of about 3,000-8,000. In total there are 125 polygons.
Is that normal? Can I in some way, reduce the granularity of the polygons? CPU consumption peaks at over 190% on iPhone 5, and it takes a few minutes before the first overlays pop up.
One thing you might consider is using TileMill to render the Shapefile down into raster tiles with alpha transparency. You can then use that in either MapKit or the Mapbox iOS SDK. It will be highly performant, plus you can still use interactivity going the Mapbox route. Take this map, which was made from Shapefile data in TileMill: https://a.tiles.mapbox.com/v3/newamerica.motw_poverty/page.html#6/40.086/-95.471 The same way that the mouseovers work on the web, you could use Mapbox's RMInteractiveSource API to query and show on tap or other gestures.

Is MapKit's scaling behavior broken in the iOS simulator?

I'm working on an app that tries to keep two MKMapView's synchronized with respect to scale. I spent a few days debugging on the iOS simulator, and was getting increasingly frustrated that attempts to set a map view's scale, whether by setting the region or the MapRect, yielded results wildly different than I expected.
When I tried the app on the most convenient iOS device at hand (iPad mini), MapKit was working mostly as expected and I was able to resolve the remaining nuances quickly. At this point, I can get both maps on the device to display identical areas (down to 10m or less in each dimension); on the simulator, setting a map's scale yields a result sometimes off as much as 2x the scale expected.
Has anybody else experienced this disparity between the simulator and the device? If so, any explanation?
Thanks in advance.
the scale of mapkit cannot be set accuratley, neither for one view, nor for both.
At least this is valid before ios 6.
The reason is that mapkit zooms to the next suitable google resoultion, if you want lets say a scale 5% bigger than the next google map, it will still snap to the google resol.
so up to and including ios 5 it is not possible to programatically zoom to an exact value. (i saw no post that mentioned the behavior in ios 6 apple maps)
So in your case, one view could match one of the 16 google zoom levels, while the other view falls in another zoom level.

Resources