简体   繁体   中英

iOS 13.2 MKTileOverlay occasionally won't render

I'm having an issue where in iOS 13.2 (probably also from iOS 13), loading offline map tile using MKTileOverlay occasionally won't be able to render, leaving the tile blank, there seems to be no issue with MKTileOverlay 's subclass at all as it worked well in iOS 12 and below. I have 2 MKTileOverlay class (1 add grid and 1 load map tile file, default MKTileOverlay ), both won't be able to load on that blank tile with default MKTileOverlayRenderer , other overlays seems to appear fine.

The issue seems to be resolved itself if I go to home screen and go back to the app, causing the tiles to reload. Is this a bug from iOS MapKit itself? Does anyone have temporary solution for this? Thank you.

Code for adding overlay:

let overlay = MKTileOverlay(urlTemplate: urlTemplate)
overlay.canReplaceMapContent = true
overlay.maximumZ = 19
mapView.insertOverlay(overlay, at: 0, level: .aboveLabels)

Renderer:

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKTileOverlay {
        let renderer = MKTileOverlayRenderer(tileOverlay: overlay as! MKTileOverlay)
        return renderer
    }

    return MKOverlayRenderer()
}

在此处输入图片说明

As I noted in a comment to the original question I was having the same problem, but it is now largely resolved, so I thought I'd post what worked for me.

The problem for me occurred in the following method

- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData * __nullable tileData, NSError * __nullable error))result{

where the custom tile would fail to load even when it was being presented with what appeared to be valid NSData.

I found that the problem was reduced if I used jpegs instead of pngs for my custom tiles, but it was only when I changed the way that I was handling the tile data did the problem largely go away. (I largely, because I still get the occasional unloaded tile, but I'd say it's 100x less often than I was getting them before).

The following method is my Xamarin.iOS implementation of it, but you should be able to see the principle for Swift or Objective C.

The key is the difference in the way the NSData is created. Instead of calling the UrlForTilePath method, I create a UIImage from the tile path and then use the UIImageJPEGRepresentation (AsJPEG in C#) to create the NSData.

   public override void LoadTileAtPath(MKTileOverlayPath path, MKTileOverlayLoadTileCompletionHandler result)
    {
        //I was using this prior to ios 13.2

        //NSUrl url = this.URLForTilePath(path);
        //NSData tileData = NSData.FromFile(url.AbsoluteString);
        //result(tileData, null);

        //Now I use this

        String folderPath = "tiles/" + path.Z + "/" + path.X + "/";
        String tilePath = NSBundle.MainBundle.PathForResource(path.Y.ToString(), "jpg", folderPath);
        String blankPath = NSBundle.MainBundle.PathForResource("tile", "jpg");

        try
        {
            //does the file exist?
            UIImage tile;
            if (File.Exists(tilePath))
            {
                tile = UIImage.FromFile(tilePath);
                if (tile == null)
                {
                    Console.WriteLine("Error Loading " + path.Z + " " + path.Y + " " + path.X);
                    //This may be redundant, as I'm not getting any errors here, even when the tile doesn't display
                }
            }
            else
            {
                tile = UIImage.FromFile(blankPath);
            }

            NSData tileData = tile.AsJPEG();
            result(tileData, null);
        }
        catch (Exception ex)
        {

        }
    }

It is clearly a MapKit issue/bug.

I've also open a feedback ticket since the 9th of December 2020.

The root of this issue is not very sure.

MapKit and specially MKTileOverlay always had/have some issues with "heavy" tiles like PNG 24bit. When the MKTileOverlay use PNG (heavy tiles), the tiles sometimes are flashing and the map is continuously reloading especially with wide screens (iPad pro etc..)

So, since the JPEG tiles are often lighter than PNG, JPEG can be a workaround.

BUT , this new iOS 13.2+ issue is not the same! Random tiles are not rendered. If you remove and readd the MKTileOverlay or call the reloadData method of MKTileOverlayRenderer, the missing tiles will be rendered and it will be other random tiles that which be missing.

The real solution of the issue is to open a feedback ticket: https://feedbackassistant.apple.com

Edit : I've just tried to replace my 8bit PNG by 85% JPEG on the very simple MKTileOverlay project sample i've sent to Apple in my ticket. Same issue... no improvement.

Edit 2 : Loading the NSData into an UIImage then using UIImageRepresentationJPEG seems to do the trick... Ugly...

- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData * _Nullable, NSError * _Nullable))result
{
    NSString *tilePath = [self PATHForTilePath:path];
    NSData *data = nil;

    if (![[NSFileManager defaultManager] fileExistsAtPath:tilePath])
    {
        NSLog(@"Z%ld/%ld/%ld does not exist!", path.z, path.x, path.y);
    }
    else
    {
        NSLog(@"Z%ld/%ld/%ld exist", path.z, path.x, path.y);

        UIImage *image = [UIImage imageWithContentsOfFile:tilePath];
        data = UIImageJPEGRepresentation(image, 0.8);
        // Instead of: data = [NSData dataWithContentsOfFile:tilePath];

        if (data == nil)
        {
            NSLog(@"Error!!! Unable to read an existing file!");
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        result(data, nil);
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM