我正在尝试将地理上较大(~1km)的单个图像作为叠加层添加到 MkMapView 中。最终我想每秒左右更新一次这张图片。
我根据我在此处找到的代码创建了一个 MkOverlay 子类,并将其添加到 Mapkit 视图中。它绘制在正确的位置,它随着地图的移动而移动和缩放,但如果我尝试旋转它,屏幕会锁定,并且它开始以我上次测试中 10Mb/秒的速度增加内存,这可能与图像的大小。这会一直持续到内存耗尽或我退出为止。 这是在模拟器或真实设备上。这次它没有调用我的任何代码或产生任何输出,因为我对 swift 非常陌生(< 1 month) I am at a bit of a loss to know how else I can debug it.
我复制了这个相同的应用程序,只需更改我需要更改的最小值(即,将 UI 更改为 NS)以作为地图应用程序运行,整个应用程序运行并可以正确旋转。
我制作了一个精简的应用程序,其中包含尽可能少的代码,但它也会崩溃。
class ImageOverlay : NSObject, MKOverlay {
let image:UIImage
let boundingMapRect: MKMapRect
let coordinate:CLLocationCoordinate2D
init(image: UIImage, rect: MKMapRect) {
self.image = image
self.boundingMapRect = rect
var coord = rect.origin
coord.x += rect.size.width / 2
coord.y += rect.size.height / 2;
self.coordinate = CLLocationCoordinate2D(latitude: coord.x, longitude: coord.y)
}
}
class ImageOverlayRenderer : MKOverlayRenderer {
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext)
{
guard let overlay = self.overlay as? ImageOverlay else {
return
}
let rect = self.rect(for: overlay.boundingMapRect)
context.saveGState()
context.setAlpha(0.6)
context.draw(overlay.image.cgImage!, in: rect, byTiling: false)
context.flush()
context.restoreGState()
}
}
struct MapView: UIViewRepresentable {
@Binding var imgOver: ImageOverlay?
let mapViewDelegate = MapViewDelegate()
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame:.zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
view.delegate = mapViewDelegate
view.translatesAutoresizingMaskIntoConstraints = false
view.mapType = .hybrid
addImage(to: view)
}
}
extension MapView {
func addImage(to view: MKMapView) {
if !view.overlays.isEmpty {
view.removeOverlays(view.overlays)
}
guard let img = imgOver else { return }
let mapRect = img.boundingMapRect
view.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100), animated: true)
view.addOverlay(img)
}
}
class MapViewDelegate: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
ImageOverlayRenderer(overlay: overlay)
}
}
struct ContentView: View {
@State var imageOverlay: ImageOverlay?
var body: some View {
MapView(imgOver:$imageOverlay)
.onAppear {
let image = UIImage(named: "portland.png")!
let p1 = MKMapPoint( CLLocationCoordinate2DMake(50.564479946138384, -2.4423953407134054))
let p2 = MKMapPoint( CLLocationCoordinate2DMake(50.57264968724567, -2.415437272738347))
let bounds = MKMapRect(x: fmin(p1.x,p2.x), y: fmin(p1.y,p2.y), width: fabs(p1.x-p2.x), height: fabs(p1.y-p2.y));
self.showImage(image:image, bounds:bounds )
}
}
}
private extension ContentView {
func showImage(image:UIImage?, bounds:MKMapRect) {
if image == nil {
return
}
self.imageOverlay = ImageOverlay(image:image!, rect:bounds)
}
}
任何指出我做错了什么或如何更好地调试代码之外的内存丢失的指示将不胜感激。
经过研究,这是我从这里得到的 MapView UIRepresentable 示例。 我怀疑 view.translatesAutoresizingMaskIntoConstraints 导致了这个问题。为了供其他尝试执行此操作的人参考,我将 MapView 替换为:
struct MapView: UIViewRepresentable {
@Binding var imgOver: ImageOverlay?
let mapViewDelegate = MapViewDelegate()
func makeUIView(context: Context) -> MKMapView {
let view = MKMapView(frame:.zero)
view.delegate = mapViewDelegate
view.mapType = .hybrid
return view
}
func updateUIView(_ view: MKMapView, context: Context) {
addImage(to: view)
}
}
现在覆盖层可以完全按照所有用途的预期工作。