Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Marker performance iOS, crash with result "((null)) was false: Reached the max number of texture atlases, can not allocate more."

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.

image when radius is 5km

image when radius is 2.4km

image when radius is 1.7km

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:

  1. If it is approaching a green marker, then it will turn to a blue marker
  2. If it is going far from a blue marker, then it will turn to a green marker.
like image 453
manish_kumar Avatar asked Apr 01 '15 12:04

manish_kumar


2 Answers

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
}
like image 126
Cymric Avatar answered Oct 17 '22 05:10

Cymric


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
}

}

like image 41
Bhas Avatar answered Oct 17 '22 04:10

Bhas