从iOS照片库获取城市和州

问题描述 投票:0回答:1

在 MacOS 上,我可以通过查询 Photos.sqlite 数据库从所有 90,000 张照片中获取地名。

我现在正在尝试在 iOS 中做类似的事情,但只找到了

coordinate.latitude
coordinate.longitude

我看到有一个

reverseGeocodeLocation
接受坐标并返回 CLPlacemark,但每个应用程序的地理编码请求都有速率限制。

如果我查看 iPhone 上的“照片”应用程序,我可以看到我的照片已经有地名元数据,它是否在某个 API 中公开?

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
                    ))
                }
            }
        }
    }
}
ios swift
1个回答
0
投票
  • 您可以批量处理位置并通过缓存地理编码结果来避免重复,而不是查询每张照片。

  • 通过避免过多的同时请求来有效地使用

    CLGeocoder

  • 不幸的是,详细的地名元数据(如照片应用程序中显示的元数据)无法通过照片框架公开。

这是代码的更正版本:

import Photos
import CoreLocation

struct PhotoLocation {
    let id: String
    let coordinate: CLLocationCoordinate2D
    let creationDate: Date
    let filename: String
    let placeName: String? // Optional for reverse geocoded place names
}

class PhotoManager {
    private let geocoder = CLGeocoder()
    private var geocodeCache = [CLLocationCoordinate2D: String]() // Cache for geocoded locations
    private(set) var photoLocations: [PhotoLocation] = []

func fetchPhotoLocations() {
    let fetchOptions = PHFetchOptions()
    fetchOptions.includeHiddenAssets = false
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    
    let assets = PHAsset.fetchAssets(with: fetchOptions)
    
    assets.enumerateObjects { [weak self] (asset, index, stop) in
        guard let self = self else { return }
        
        if let location = asset.location {
            let resources = PHAssetResource.assetResources(for: asset)
            let filename = resources.first?.originalFilename ?? "Unknown"
            
            let coordinate = location.coordinate
            
            // Check cache before making a geocoding request
            if let cachedPlaceName = self.geocodeCache[coordinate] {
                self.addPhotoLocation(asset: asset, coordinate: coordinate, filename: filename, placeName: cachedPlaceName)
            } else {
                // Perform reverse geocoding
                self.geocoder.reverseGeocodeLocation(location) { [weak self] (placemarks, error) in
                    guard let self = self else { return }
                    
                    let placeName = placemarks?.first?.locality ?? placemarks?.first?.name
                    if let placeName = placeName {
                        self.geocodeCache[coordinate] = placeName // Cache the result
                    }
                    
                    self.addPhotoLocation(asset: asset, coordinate: coordinate, filename: filename, placeName: placeName)
                }
            }
        }
    }
}

private func addPhotoLocation(asset: PHAsset, coordinate: CLLocationCoordinate2D, filename: String, placeName: String?) {
    DispatchQueue.main.async {
        let photoLocation = PhotoLocation(
            id: asset.localIdentifier,
            coordinate: coordinate,
            creationDate: asset.creationDate ?? Date(),
            filename: filename,
            placeName: placeName
        )
        self.photoLocations.append(photoLocation)
    }
}

对于大型照片库,您可以:

  • 限制一次处理的照片数量。
  • 为批处理元数据添加分页。
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.