ios 在Compose Multiplatform中使用MKMapViewDelegateProtocol接收pin选定事件

pnwntuvh  于 2023-10-21  发布在  iOS
关注(0)|答案(1)|浏览(114)

我正在尝试使用Compose Multiplatform来实现一个针对Android和iOS的应用程序。该应用程序包含一个Map,这部分应使用Android上的谷歌Map和iOS上的苹果Map每个平台实现。
我有一个Composable函数,它需要Android和iOS的特定平台实现

@Composable
expect fun MyMap(items: List<Item>, onItemClicked: (Item) -> Unit)

我看到的问题是MKMapViewDelegateProtocol.mapView在Kotlin中可能非常模糊。但我不知道如何在KMP中实现该协议,以便它被iOS应用程序选中,我得到了pin selected事件。
目前,iOS实现如下所示

@Composable
actual fun MyMap(items: List<Item>, onItemClicked: (Item) -> Unit) {
  UIKitView(
    modifier = Modifier.fillMaxSize(),
    factory = {
      MKMapView().apply {
        setDelegate(MKDelegate { annotation ->
          annotation?.title?.let { title ->
            val item = items.find { it.title == title }
            onItemClicked(item)
          } ?: onItemClicked(null)
        })
      }
    },
    update = {
      val pins = items.map { item ->
        val pin = MKPointAnnotation()
        val coordinates = item.coordinates                 

        pin.setCoordinate(CLLocationCoordinate2DMake(coordinates.latitude.coordinate, coordinates.longitude.coordinate))
        pin.setTitle(vendingMachine.address)
        pin
      }
      it.addAnnotations(pins)
    }
  )
}

图钉在Map上显示正确,但当用户选择图钉时,我没有收到来自代理的任何点击事件。
我试着像这样实现MKMapView.setDelegate所需的MKMapViewDelegateProtocol

private class MKDelegate(
  private val onAnnotationClicked: (MKPointAnnotation?) -> Unit
) : NSObject(), MKMapViewDelegateProtocol {
  override fun mapView(mapView: MKMapView, didSelectAnnotationView: MKAnnotationView) {
    val annotation = didSelectAnnotationView.annotation as MKPointAnnotation
    onAnnotationClicked(annotation)
  }
}
8iwquhpp

8iwquhpp1#

在iOS世界中,名为delegate的字段通常存储对对象的弱引用-这意味着此对象不负责对象的生命周期,因此当对象被销毁时,该属性会自动设置为null。这样做是为了防止保留周期。请参阅this question以了解详细信息。如果您计划从Kotlin实现更多iOS功能,请查看一些关于自动引用计数(ARC)的文章。
Kotlin有它自己的内存模型,但是当你从Kotlin代码创建ObjC对象时,它们遵循ObjC内存模型。
因此,当你用setDelegate(MKDelegate ...创建一个对象时,它会立即被销毁,因为这个对象引用没有存储在任何强引用中。你需要把它分开存放。
例如,可以使用remember

val delegate = remember {
    MKDelegate { annotation ->
        // ...
    }
}
UIKitView(
    modifier = Modifier.fillMaxSize(),
    factory = {
        MKMapView().apply {
            setDelegate(delegate)
        }
    },

相关问题