You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVAudioPlayer持续重启求助:基于速度触发的地图警示音异常

问题解决:避免速度更新时警示音反复重启

你的核心问题是每次位置更新都调用play(),导致音频从头重复播放,同时还存在音频播放器未初始化的问题。以下是针对性的修复方案:

关键问题分析

  1. 音频播放器player从未初始化:sesFonk()方法没被调用,导致player始终为nil,一开始根本无法播放声音。
  2. 无状态判断:只要速度≥7就调用play(),而AVAudioPlayer的play()在播放中会从头重启,导致声音反复中断。

修复后的完整代码

import UIKit
import MapKit
import CoreLocation
import AVFoundation

class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
    
    @IBOutlet weak var imageLabel: UIImageView!
    @IBOutlet weak var mapView: MKMapView!
    var player: AVAudioPlayer!
    var locationManager = CLLocationManager()
    
    // 新增状态变量:记录警示音是否正在播放
    var isWarningSoundPlaying = false

    override func viewDidLoad() {
        super.viewDidLoad()
        
        mapView.delegate = self
        imageLabel.isHidden = true
        
        // 初始化音频播放器(必须调用,否则player为nil)
        sesFonk()
        
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // 安全获取最新位置,避免数组越界
        guard let sonKonum = locations.last else { return }
        
        let konum = sonKonum.coordinate
        let span = MKCoordinateSpan(latitudeDelta: 0.03, longitudeDelta: 0.03)
        let bolge = MKCoordinateRegion(center: konum, span: span)
        mapView.setRegion(bolge, animated: true)
        mapView.showsUserLocation = true
        
        let currentSpeed = Int(sonKonum.speed)
        print(currentSpeed)
        
        if currentSpeed >= 7 {
            imageLabel.isHidden = false
            // 只有当声音未播放时,才启动播放
            if !isWarningSoundPlaying {
                player?.play()
                isWarningSoundPlaying = true
            }
        } else {
            imageLabel.isHidden = true
            // 只有当声音正在播放时,才停止并重置播放位置
            if isWarningSoundPlaying {
                player?.stop()
                player?.currentTime = 0
                isWarningSoundPlaying = false
            }
        }
    }

    func sesFonk() {
        guard let url = Bundle.main.url(forResource: "yavas", withExtension: "mp3") else {
            print("错误:找不到音频文件yavas.mp3")
            return
        }
        
        do {
            player = try AVAudioPlayer(contentsOf: url)
            // 设置无限循环播放(适合警示场景)
            player.numberOfLoops = -1
            // 预加载音频,避免播放卡顿
            player.prepareToPlay()
        } catch {
            print("初始化音频播放器失败:\(error.localizedDescription)")
        }
    }
}

核心修改说明

  • 新增状态变量isWarningSoundPlaying:用来追踪当前警示音的播放状态,只有状态变化时才执行播放/停止操作,避免重复触发。
  • 初始化音频播放器:在viewDidLoad中调用sesFonk(),确保player被正确初始化。
  • 优化播放逻辑:仅当速度超过阈值且声音未播放时启动播放;速度低于阈值且声音在播放时停止并重置播放位置。
  • 增强错误处理:添加音频文件不存在的判断,输出更清晰的错误信息。
  • 设置循环播放:将player.numberOfLoops设为-1,让警示音持续播放直到速度下降。

额外注意事项

  1. 确认yavas.mp3已添加到项目中,且在Target Membership中勾选了当前项目。
  2. CLLocation.speed的单位是米/秒,7m/s相当于约25km/h。如果需要用公里/小时作为阈值,可将速度转换为:let currentSpeed = Int(sonKonum.speed * 3.6)。
  3. 确保Info.plist中添加了NSLocationWhenInUseUsageDescription权限描述,否则无法获取位置信息。

内容的提问来源于stack exchange,提问作者Yavuz Ulgar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:35:26