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

如何从iOS照片库中直接获取城市与州等地名信息?

iOS相册直接读取照片内置地名元数据方案

我在MacOS上可以通过查询Photos.sqlite数据库获取9万张照片的地名信息,但在iOS上目前只能拿到照片的经纬度坐标。我知道用reverseGeocodeLocation可以通过坐标转CLPlacemark,但这个接口有应用级速率限制。观察iPhone相册发现照片本身就带地名元数据,请问有没有对应的API能直接读取这些信息?

当前我的Swift代码:

private func fetchPhotoLocations() {
    let fetchOptions = PHFetchOptions()
    fetchOptions.includeHiddenAssets = false
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    
    let assets = PHAsset.fetchAssets(with: fetchOptions)
    
    assets.enumerateObjects { (asset, index, stop) in
        if let location = asset.location {
            let resources = PHAssetResource.assetResources(for: asset)
            let filename = resources.first?.originalFilename ?? "Unknown"
            
            let options = PHAssetResourceRequestOptions()
            options.isNetworkAccessAllowed = false
            
            if let resource = resources.first {
                PHAssetResourceManager.default().requestData(for: resource, options: options) { (data) in
                    
                } completionHandler: { (error) in
                    if let error = error {
                        print("Error loading resource: \(error)")
                    }
                }
                
                DispatchQueue.main.async {
                    self.photoLocations.append(PhotoLocation(
                        id: asset.localIdentifier,
                        coordinate: location.coordinate,
                        creationDate: asset.creationDate ?? Date(),
                        filename: filename
                    ))
                }
            }
        }
    }
}

直接读取内置地名的两种方法

Photos框架的PHAsset没有直接暴露地名属性,但照片的EXIF/GPS元数据里确实存储了已解析的地名信息,可通过以下方式提取:

1. 从PHAssetResource数据解析元数据

你当前的代码已经在请求资源数据,但没做解析。可以用CGImageSource从数据中提取GPS相关字段:

private func fetchPhotoLocations() {
    let fetchOptions = PHFetchOptions()
    fetchOptions.includeHiddenAssets = false
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    
    let assets = PHAsset.fetchAssets(with: fetchOptions)
    
    assets.enumerateObjects { (asset, index, stop) in
        guard let location = asset.location else { return }
        let resources = PHAssetResource.assetResources(for: asset)
        let filename = resources.first?.originalFilename ?? "Unknown"
        
        let options = PHAssetResourceRequestOptions()
        options.isNetworkAccessAllowed = false
        
        guard let resource = resources.first else { return }
        
        PHAssetResourceManager.default().requestData(for: resource, options: options) { data in
            // 解析图片元数据
            guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else { return }
            let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any]
            let gpsProperties = properties?[kCGImagePropertyGPSDictionary as String] as? [String: Any]
            
            // 提取地名相关字段
            let locationName = gpsProperties?[kCGImagePropertyGPSLocationName as String] as? String
            let city = gpsProperties?[kCGImagePropertyGPSCity as String] as? String
            let country = gpsProperties?[kCGImagePropertyGPSCountry as String] as? String
            
            DispatchQueue.main.async {
                self.photoLocations.append(PhotoLocation(
                    id: asset.localIdentifier,
                    coordinate: location.coordinate,
                    creationDate: asset.creationDate ?? Date(),
                    filename: filename,
                    locationName: locationName,
                    city: city,
                    country: country
                ))
            }
        } completionHandler: { error in
            if let error = error {
                print("Error loading resource: \(error)")
            }
        }
    }
}

2. 通过PHContentEditingInput获取元数据(更高效)

这种方式不需要读取整个文件数据,直接通过资源URL解析,适合批量处理大量照片:

private func fetchPhotoLocations() {
    let fetchOptions = PHFetchOptions()
    fetchOptions.includeHiddenAssets = false
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    
    let assets = PHAsset.fetchAssets(with: fetchOptions)
    
    assets.enumerateObjects { (asset, index, stop) in
        guard let location = asset.location else { return }
        let filename = asset.value(forKey: "filename") as? String ?? "Unknown"
        
        let editOptions = PHContentEditingInputRequestOptions()
        editOptions.isNetworkAccessAllowed = false
        
        asset.requestContentEditingInput(with: editOptions) { input, info in
            guard let input = input, let imageURL = input.fullSizeImageURL else { return }
            
            guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, nil) else { return }
            let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any]
            let gpsDict = properties?[kCGImagePropertyGPSDictionary as String] as? [String: Any]
            
            let locationName = gpsDict?[kCGImagePropertyGPSLocationName as String] as? String
            let city = gpsDict?[kCGImagePropertyGPSCity as String] as? String
            let country = gpsDict?[kCGImagePropertyGPSCountry as String] as? String
            
            DispatchQueue.main.async {
                self.photoLocations.append(PhotoLocation(
                    id: asset.localIdentifier,
                    coordinate: location.coordinate,
                    creationDate: asset.creationDate ?? Date(),
                    filename: filename,
                    locationName: locationName,
                    city: city,
                    country: country
                ))
            }
        }
    }
}

注意事项

  • 部分照片可能未写入地名元数据,此时仍需降级使用reverseGeocodeLocation,可通过批量缓存、分时段请求规避速率限制。
  • 不同设备/拍摄软件的EXIF字段可能有差异,需多测试几种字段(比如部分照片会把地名存在自定义字段里)。
  • 必须确保已获取PHPhotoLibrary的访问权限,否则无法读取照片资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:43:12