通过URL下载GMSMarker图标

E-R*_*die 5 ios sdwebimage google-maps-sdk-ios

将图标设置为GMSMarkerin Google Maps SDK需要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)
Run Code Online (Sandbox Code Playgroud)

从上面提供的代码中,我在第一次加载数据时遇到了问题,因为引脚显示在地图上但没有图像.如果我createMarkers()在一段时间后再次打电话,图标会正确加载.

我不知道为什么会发生这种情况,有什么建议或提示来解决这个问题?

hoa*_*hou 6

只需使用 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
Run Code Online (Sandbox Code Playgroud)


E-R*_*die 2

好吧,当时我对并发了解不多,看到所有答案并没有真正解决我真正想要的问题。

问题

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

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

还关于为什么它在重新加载时有效?SDWebImage重新加载时,已经下载并缓存了图片,所以下次没有延迟,直接绑定到marker

解决方案

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

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你看到我引入了一个名为 的助手applyImage(from:, to:),它基本上没有做任何特别的事情,只是从 下载图像URL并将其绑定到 type 的参数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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

另外还有一个将图像裁剪为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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

输出

演示