【问题标题】:GMSMarker icon download via URL通过 URL 下载 GMSMarker 图标
【发布时间】:2014-06-12 11:06:44
【问题描述】:

Google Maps SDK 中将图标设置为GMSMarker 需要UIImage,但目前我的要求是从特定的URL 下载它

问题

问题是有时只显示最后一项。这是关于我如何创建标记的代码(在 Swift 中更新

func createMarkers() {
    mapView.clear()

    let mapCoordinates: [CLLocationCoordinate2D] = coordinates()
    let iconURLs: [URL] = imageURLs()

    var marker = GMSMarker()
    for i in 0..<mapCoordinates.count {
        let imageURL = iconURLs[i]

        marker = GMSMarker()
        marker.position = mapCoordinates[i]
        marker.map = mapView

        downloadImage(from: imageURL) { image in
            marker.icon = image
        }
    }
}

// It is a helper function calling `SDWebImage` which caches the `UIImage` based on its `URL` string
func downloadImage(from url: URL, completion: @escaping (UIImage) -> Void)

根据上面提供的代码,我在第一次加载数据时遇到了问题,因为图钉显示在地图上但没有图像。如果我在一段时间后再次调用createMarkers(),则图标已正确加载。

我不知道为什么会这样,有什么建议或提示可以解决这个问题吗?

【问题讨论】:

  • 您好,您有什么解决办法吗??我想在标记的图像上实现延迟加载,但没有显示图像。我正在尝试使用 AsyncImageview 类。请告诉我
  • @Nisha 你不能用它做延迟加载。您需要异步下载所有图像,下载完成后,添加图钉的图像。
  • 好的,谢谢您的回复。现在它使用 Grand Central Dispatch 解决了
  • @Nisha 是的,您可以异步下载它们,但是您如何跟踪正在下载的图像?
  • 现在我不需要跟踪.. 我使用了 dispatch_async(myQueue, ^{}); for 循环中的方法可能是我可以使用 objectAtIndex:我不确定

标签: ios google-maps-sdk-ios sdwebimage


【解决方案1】:

只使用 SDWebimage,而 .iconView 不是 .icon

let imageView = UIImageView(image: pinImage)
imageView.sd_setImage(with: URL(string: "https://pbs.twimg.com/profile_images/469017630796296193/R-bEN4UP.png"), placeholderImage: pinImage)
marker.iconView = imageView

【讨论】:

    【解决方案2】:

    好吧,那时我对并发还不是很了解,看到所有的答案并没有真正解决我真正想到的问题。

    问题

    由于从URL (downloadImage(from url: URL, completion: @escaping (UIImage) -&gt; Void)) 下载图像是一个后台操作,因此在下载图像时,marker 已经超出范围,在循环中再次被初始化。

    这样就无法知道哪个图像绑定到哪个标记。

    还有关于为什么在重载时会起作用?,重载时的SDWebImage已经下载并缓存了图片,所以下次没有延迟,只是绑定到@ 987654328@直接。

    解决方案

    将可变变量标记作为不可变值移动到循环内。

    func createMarkers() {
        let mapCoordinates: [CLLocationCoordinate2D] = coordinates()
        let iconURLs: [URL] = imageURLs()
    
        for i in 0..<mapCoordinates.count {
            let imageURL = iconURLs[i]
    
            let marker = GMSMarker()
            marker.position = mapCoordinates[i]
            marker.map = mapView
            applyImage(from: imageURL, to: marker)
        }
    }
    

    现在你看到我介绍了一个名为 applyImage(from:, to:) 的助手,它基本上没有什么特别之处,只是从 URL 下载图像并将其绑定到 GMSMarker 类型的参数。

    func applyImage(from url: URL, to marker: GMSMarker) {
        DispatchQueue.global(qos: .background).async {
            guard let data = try? Data(contentsOf: url),
                let image = UIImage(data: data)?.cropped()
                else { return }
    
            DispatchQueue.main.async {
                marker.icon = image
            }
        }
    }
    

    另外还有一个将图片裁剪成44pt X 44pt的扩展,这个是不对的,只是用来预览已经加载的内容。

    extension UIImage {
    
        func cropped() -> UIImage? {
            let cropRect = CGRect(x: 0, y: 0, width: 44 * scale, height: 44 * scale)
    
            guard let croppedCGImage = cgImage?.cropping(to: cropRect) else { return nil }
    
            return UIImage(cgImage: croppedCGImage, scale: scale, orientation: imageOrientation)
        }
    }
    

    注意:整个 ViewController 代码可以在我写的 Gist 找到!

    输出

    【讨论】:

    • 很棒的解决方案哥们
    【解决方案3】:

    也许试试这个...在完成块内移动几行,使用标记...

    [imageView setImageWithURL:[NSURL URLWithString:placeObject.photoPath] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType)
    {
        image = [self image:image ByScalingAndCroppingForSize:CGSizeMake(44, 44)];
        [marker setIcon:image];
        [pins addObject:marker]; //assuming you use pins later
        marker.map = mapView_;
    }];
    

    因为您已经有了正在处理的标记。当然,您需要注意您的错误处理程序。

    【讨论】:

    • 我以前试过这个,也没有运气!我没有错误,但只是那个标记忽略了图像。
    • 然后验证你的缓存类型。
    • 我没有缓存问题,也没有错误,我只需要如何正确加载标记中的图像
    • 您之前说过“如果我从网络重新加载数据并再次使用此方法添加图钉,则图像会加载到标记上。”不是这样吗?
    • 是的,但我想在标记上加载图像而无需重新加载。有可能正在下载图像,当我按下刷新时,图像已经在缓存中!
    【解决方案4】:

    同样的问题。这是我的解决方案:添加 2 次​​p>

    这是我的代码:D

    - (void)addMarkers {
        //for() {
             NSString *avatarLink = [tempLocation.userInfo objectForKey:@"avatar"];
            GMSMarker *marker = [self addMarker:tempLocation andCustomView:customView];
    
            [customView.imageGame setImageWithURL:[NSURL URLWithString:avatarLink] placeholderImage:[UIImage imageNamed:LOADING_ICON] options:SDWebImageCacheMemoryOnly completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
                marker.icon = [self captureView:customView];
            }];
        //}
    }
    - (GMSMarker*)addMarker: (FriendLocation*)tempLocation andCustomView: (FriendCustomInforwindow*)customView {
        GMSMarker *marker = [[GMSMarker alloc] init];
        marker.position = CLLocationCoordinate2DMake(tempLocation.coordinate.latitude, tempLocation.coordinate.longitude);
        marker.animated=YES;
        marker.infoWindowAnchor = CGPointMake(0.5, 2.37);
        marker.icon = [self captureView:customView];
        marker.map = mapView;
        [markersArray addObject:marker];
        return marker;
    }
    

    【讨论】:

    • '[self captureView:customView];' 有什么作用?
    • 哦,我自定义了 InfoWindow。我必须将 uiview 转换为 uiimage。在 customView 中,我添加了一个 uiimageview:它命名为 imageGame。
    • 和我的函数没有区别,只是思路一样,只是代码不同而已!
    • 对,你必须等待。或者您需要在添加标记之前下载并缓存它。
    • 无论如何感谢您的代码,但我的问题是如何正确加载它们,因为我在地图上有太多引脚
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 2020-06-03
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多