ios - 无法从内存堆栈中释放手势识别器
问题描述
我正在尝试在我的 mapView 上实现自定义手势识别器,以防止用户放大或缩小超过 MKCoordinateSpan 设置的某个阈值。
mapView 的 ViewController 是标签栏控制器的一部分,所以每次视图消失时我都会删除 mapView 并重新添加它以用于内存目的。
由于我添加了自定义手势识别器,因此当视图消失时内存不会被释放。除了从 mapView 中删除手势识别器之外,我还缺少什么?
地图视图控制器:
class MapViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
loadMapView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if mapView == nil {
loadMapView()
}
}
override func viewDidDisappear(_ animated:Bool) {
super.viewDidDisappear(animated)
self.applyMapViewMemoryFix()
}
func loadMapView() {
self.edgesForExtendedLayout = []
setMapView()
}
func setMapView() {
if self.mapView == nil {
addMapView()
}
mapView.delegate = self
mapView.mapType = .mutedStandard
mapView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
}
func addMapView() {
mapView = MKMapView()
mapView.frame = self.navigationController!.view.bounds
mapView.mapType = MKMapType.standard
mapView.isZoomEnabled = true
mapView.isScrollEnabled = true
self.view.addSubview(mapView)
}
func applyMapViewMemoryFix() {
for recognizer in (self.mapView?.gestureRecognizers)! {
if recognizer is WildCardGestureRecognizer {
self.mapView.removeGestureRecognizer(recognizer)
}
}
self.mapView.showsUserLocation = false
self.mapView.delegate = nil
self.mapView.removeFromSuperview()
self.mapView = nil
}
}
我为手势识别器设置边界的扩展:
extension MapViewController: MKMapViewDelegate {
// View Region Changing
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let northernBorder = 32.741152
let southernBorder = 32.731461
let easternBorder = -117.143622
let westernBorder = -117.157399
var latitude = mapView.region.center.latitude
var longitude = mapView.region.center.longitude
if (mapView.region.center.latitude > northernBorder) {
latitude = northernBorder
}
if (mapView.region.center.latitude < southernBorder) {
latitude = southernBorder
}
if (mapView.region.center.longitude > easternBorder) {
longitude = easternBorder
}
if (mapView.region.center.longitude < westernBorder) {
longitude = westernBorder
}
let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)
tapInterceptor.touchesBeganCallback = {_, _ in
mapView.isZoomEnabled = true
}
tapInterceptor.touchesMovedCallback = {_, _ in
if tapInterceptor.scale < 1 {
if (latitude != mapView.region.center.latitude || longitude != mapView.region.center.longitude)
|| ((mapView.region.span.latitudeDelta > (northernBorder - southernBorder) )
|| (mapView.region.span.longitudeDelta > (easternBorder - westernBorder))) {
let span = MKCoordinateSpan.init(latitudeDelta: 0.007, longitudeDelta: 0.007)
if mapView.region.span.latitudeDelta > span.latitudeDelta || mapView.region.span.longitudeDelta > span.longitudeDelta {
mapView.isZoomEnabled = false
} else {
mapView.isZoomEnabled = true
}
}
} else if tapInterceptor.scale > 1 {
let minimumSpan = MKCoordinateSpan.init(latitudeDelta: 0.002, longitudeDelta: 0.002)
if mapView.region.span.latitudeDelta < minimumSpan.latitudeDelta || mapView.region.span.longitudeDelta < minimumSpan.longitudeDelta {
mapView.isZoomEnabled = false
} else {
mapView.isZoomEnabled = true
}
}
}
tapInterceptor.touchesEndedCallback = {_, _ in
mapView.isZoomEnabled = true
}
mapView.addGestureRecognizer(tapInterceptor)
}
}
自定义手势识别器:
class WildCardGestureRecognizer: UIPinchGestureRecognizer {
var touchesBeganCallback: ((Set<UITouch>, UIEvent) -> Void)?
var touchesMovedCallback: ((Set<UITouch>, UIEvent) -> Void)?
var touchesEndedCallback: ((Set<UITouch>, UIEvent) -> Void)?
override init(target: Any?, action: Selector?) {
super.init(target: target, action: action)
self.cancelsTouchesInView = false
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
touchesBeganCallback?(touches, event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
touchesMovedCallback?(touches, event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesEnded(touches, with: event)
touchesEndedCallback?(touches, event)
}
override func canPrevent(_ preventedGestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
override func canBePrevented(by preventingGestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
}
解决方案
在这里声明手势时内存泄漏
let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)
.
.
.
mapView.addGestureRecognizer(tapInterceptor)
在里面regionDidChangeAnimated
,因为它被多次调用,随着区域的变化,你会在地图视图中添加很多手势,所以最好创建一个实例变量,比如
var tapInterceptor:WildCardGestureRecognizer!
并在函数中添加手势初始化和回调,然后将其称为表单viewDidLoad
同时删除@IBOutle
@IBOutlet var mapView: MKMapView!
如果您不在情节提要中制作,我也不认为删除/添加方式会有所作为,因为 IOS 中对象的释放始终不会释放整个参与部分,因此最好将地图视图保留为 1手势而不是在您选择/取消选择该点击时从丢失的那些中累积大量泄漏
推荐阅读
- iis - 带有扩展名的 URL 上的 Sitecore 管道
- c# - UTF-8 产生问号
- python - Python 3 中的异步 for 循环
- tensorflow - 将 tf.map_fn 与多个 GPU 一起使用
- firebase - 带有 Firebase 云函数错误的 SendGrid:“套接字挂起”
- ruby-on-rails - 带有 Puma 和 Nginx 配置的调试操作电缆
- android - 使用 Android Navigation Arch 组件 (JetPack) 打开相机/图库
- azure - 用于创建 Blob 的 Azure 事件触发函数
- spring-tool-suite - 无法将项目放入开发服务器
- javascript - Javascript 不适用于 cURL 或 Bat 文件。有什么想法吗?