I have integrated Google Maps in my application and also using Google Places API. After I am getting all the results from Google Places API(around 60), I am displaying them with the help of custom marker. The custom marker which I am making comprises of "Place Image" and "Place Name" because of which I have to first draw it in a UIView and then render it as a UIImage with the help of following function
- (UIImage *)imageFromView:(UIView *) view
{
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, [[UIScreen mainScreen] scale]);
} else {
UIGraphicsBeginImageContext(view.frame.size);
}
[view.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
At first all the markers are rendered and drawn easily.
Now I have a slider ranging from 100m to 5km, which acts as a search radius optimiser. As the slider will be moved(suppose to a value 2km), then all the markers are removed and only those markers whose distance from user location is less then slider value are drawn again. While I am testing the slider functionality, the application crashes saying
((null)) was false: Reached the max number of texture atlases, can not allocate more.
I am uploading screen shots for clear understanding of situation.
Please help.
Also to mention, in the screens you will see green markers as well as blue markers. Blue markers are those which are closer to user location while green ones are far off by a particular distance. As the user location will change there are 2 cases:
- If it is approaching a green marker, then it will turn to a blue marker
- If it is going far from a blue marker, then it will turn to a green marker.
I am working on an app which can have several thousand avatars moving around on the map and encounter this bug also. Clustering is a potential solution, but with this many avatars all moving, I suspect the calculations will be too CPU intensive.
The solution I use is to keep a reference to the base avatar image and use it when > 50 avatars are on the screen. Only when there are < 50 avatars on the screen, then I will generate unique images for each avatars with their names.
// GMSMarker
static var avatarDic:[String:UIImage] = Dictionary()
func removeName() {
// use a single image reference here so that google map does not crash
if let image = avatarDic[avatarBase] {
self.icon = image
}
else {
avatarDic[avatarBase] = UIImage(named:avatarBase)
self.icon = avatarDic[avatarBase]
}
}
func addName() {
self.icon = // draw name on base image
}
// GMSMapView
var userIcons:[String:MyMarker] = Dictionary()
var iconWithNames:Set<MyMarker> = Set()
func mapView(mapView: GMSMapView!, didChangeCameraPosition position: GMSCameraPosition!) {
// find visible avatars til limit
let bottomLeft = self.mapView.projection.visibleRegion().nearLeft
let topRight = self.mapView.projection.visibleRegion().farRight
var visibleMarkerSet:Set<MyMarker> = Set()
for (key, marker) in self.userIcons {
if (marker.position.latitude > bottomLeft.latitude && marker.position.latitude < topRight.latitude && marker.position.longitude > bottomLeft.longitude && marker.position.longitude < topRight.longitude) {
visibleMarkerSet.insert(marker)
}
// not showing if > 50
if (visibleMarkerSet.count > 50) {
visibleMarkerSet = Set()
break
}
}
// remove names
for markerWithName in self.iconWithNames {
if (visibleMarkerSet.contains(markerWithName) == false) {
markerWithName.removeName()
}
}
// add names
for visibleMarker in visibleMarkerSet {
visibleMarker.addName()
}
self.iconWithNames = visibleMarkerSet
}
Instead of setting marker's iconView, set marker's icon. That too initialize the image outside of for loop, as below
func displayMarkers() {
let iconImage = UIImage(named: "locationgreen")
for partner in partners {
let lat : Double = Double(partner.location?.coordinates![1] ?? 0)
let lng : Double = Double(partner.location?.coordinates![0] ?? 0)
let position = CLLocationCoordinate2D(latitude: lat, longitude: lng)
let marker = GMSMarker(position: position)
marker.title = partner.name
marker.icon = iconImage
}
}