Completion Handler重复执行问题:SwiftLocation获取用户位置回调两次
Hey there! Let's break down why your completion block and print statements are firing twice—this is a common gotcha with continuous location updates in SwiftLocation.
The Root Cause
Looking at your LocationService.getUserLocation implementation, you're using frequency:.continuous when calling Location.getLocation().
In SwiftLocation, the .continuous frequency mode doesn't just return a single location fix—it keeps monitoring for location updates and triggers the success callback every time a new (or improved) location is detected. That's why you're seeing your completion block and print statements run multiple times (in your case, twice) as the location service gets a more accurate fix after the initial one.
Fixes to Try
You have two main options depending on your use case:
1. Get a Single Location Fix (Most Likely What You Want)
If you only need to fetch the user's location once, switch the frequency to .oneShot. This tells SwiftLocation to stop monitoring after it gets the first valid location, so your completion will only run once:
struct LocationService { static func getUserLocation(completion: @escaping (CLLocation?) -> Void){ print("Attempting to get user location") Location.getLocation(accuracy: .city, frequency: .oneShot, success: { (_, location) -> Void in completion(location) }) { (request, last, error) -> Void in request.cancel() print("Location monitoring failed due to an error \(error)") completion(nil) } } }
2. Keep Continuous Updates but Filter Duplicates
If you actually need ongoing location updates but don't want to process every single one, add a flag to track whether you've already handled the first valid location. You can also cancel the request manually after getting the fix if you don't need further updates:
struct LocationService { static func getUserLocation(completion: @escaping (CLLocation?) -> Void){ print("Attempting to get user location") var hasProcessedLocation = false Location.getLocation(accuracy: .city, frequency:.continuous , success: { (request, location) -> Void in guard !hasProcessedLocation else { return } hasProcessedLocation = true completion(location) // Optional: Stop monitoring after first fix request.cancel() }) { (request, last, error) -> Void in request.cancel() print("Location monitoring failed due to an error \(error)") completion(nil) } } }
Quick Recap
The .continuous mode is designed for real-time tracking (like navigation apps). For a one-time location check, .oneShot is the right choice. If you need ongoing updates, add logic to filter out redundant callbacks based on your needs.
内容的提问来源于stack exchange,提问作者Ron Baker

