Menggunakan Tempat Asli Apple

gambar Beberapa tahun yang lalu saya mengerjakan proyek yang seharusnya memiliki fitur serupa dengan Snapchat dan pada saat yang sama menjadi aplikasi mirip Instagram yang bertema sempit. Proyek ini dikembangkan hanya untuk satu platform - iOS. Secara alami, selama pengembangan fitur utama - menerbitkan foto, klien tiba-tiba ingin menambahkan kemampuan untuk menandai tempat di mana foto itu diambil. Dalam kebanyakan kasus, banyak yang langsung mengingat Places API dari Google dan Facebook, tetapi klien tidak senang dengan kenyataan bahwa solusi ini memiliki batasan tertentu. Oleh karena itu, setelah ulasan tambahan, alternatif lain dari Apple ditemukan - CLPlacemark , yang gratis, dan dalam dokumentasi pada waktu itu tidak disebutkan batasan untuk penggunaan sehari-hari. Karena pengembangan untuk platform lain pada awalnya tidak direncanakan sama sekali, ini sepertinya pilihan yang sangat cocok.

Dokumentasi Apple menunjukkan bahwa CLPlacemark dapat memberikan banyak detail tentang poin tersebut, dan CLGeocoder juga memiliki metode yang memungkinkan Anda untuk dengan mudah mengembalikan array CLPlacemark dengan data yang diperlukan berdasarkan nama lokasi. Ternyata, semuanya bekerja tidak begitu cerah.

Kode sumbernya terlihat seperti ini:

import CoreLocation let geocoder = CLGeocoder() func findPlace(name: String) { geocoder.geocodeAddressString(name) { placemarks, error in print(placemarks) } } findPlace(name: β€œNew”) 

Dalam skenario sederhana ini, geocoder selalu mengembalikan array CLPlacemark, tetapi tangkapannya adalah array ini tidak pernah mengandung lebih dari satu elemen. Akibatnya, di seluruh layar, tempat daftar besar penempatan diharapkan seperti: New York, New Zeland, New Balance Store, dll., Saya hanya menerima satu elemen yang tidak selalu relevan dengan apa yang saya masukkan.

Setelah beberapa perjuangan yang gagal dengan CLGeocoder, kolega saya mengatakan kepada saya: "Dan Anda tidak berpikir untuk mencoba melihat, mungkin MapKit memiliki peluang yang sama?" Ternyata, MapKit memiliki MKLocalSearch , di mana kita bisa mendapatkan larik MKPlacemark , yang diwarisi dari CLPlacemark. Sirkuit tampak cukup berfungsi, jadi saya mulai mencoba pendekatan ini:

 import MapKit let request = MKLocalSearchRequest() var localSearch: MKLocalSearch? func findPlace(name: String) { request.naturalLanguageQuery = text localSearch = MKLocalSearch(request: request) localSearch?.start { (searchResponse, _) in guard let items = searchResponse?.mapItems else { return } print(items) } } findPlace(name: β€œNew) 

Hasil

Dalam hal ini, saya menerima array dengan 10 elemen CLPlacemark sebagai respons. Hasil ini tampaknya lebih dapat diterima, karena sebagai hasilnya, daftar yang cukup disediakan. Namun jauh dari biasanya, ketika Anda mulai memasukkan nama salah satu institusi yang berada di dekatnya, itu langsung menunjukkan hasil yang diinginkan. Misalnya, Domino's Pizza ada di sebelah saya. Saya ingin itu ketika saya memasukkan permintaan seperti itu dalam satu baris, pertama-tama saya harus mendapatkan perusahaan sedekat mungkin dengan saya.

Saya mulai belajar atas dasar apa array terbentuk, dan bagaimana bisa ditingkatkan. Saya telah mengidentifikasi beberapa hal yang dapat memengaruhi pemilihan parameter:

  1. Alamat IP dari mana permintaan dibuat untuk Apple. Ketika VPN dihidupkan, objek dalam hasil sudah lebih dekat ke lokasi server VPN.
  2. Lokasi pengguna saat ini. Jika koordinat pengguna saat ini dikirim ke permintaan, hasilnya akan jauh lebih akurat.
  3. Bahasa sistem perangkat.

Contoh VPN

Contoh VPN
New york

Toronto

Kyiv

London

Frankfurt


Ada kemungkinan bahwa ada faktor-faktor lain yang dapat mempengaruhi hasil pencarian, tetapi ini sudah cukup bagi saya untuk mencapai hasil yang diinginkan.

Kursus pengembangan selanjutnya adalah penggunaan lokasi perangkat saat ini.

 import UIKit import MapKit import CoreLocation final class ViewController: UIViewController, CLLocationManagerDelegate { private let locationManager = CLLocationManager() private let request = MKLocalSearch.Request() private var localSearch: MKLocalSearch? private var region = MKCoordinateRegion() override func viewDidLoad() { super.viewDidLoad() if CLLocationManager.locationServicesEnabled() { locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation() } } func searchPlace(_ place: String) { localSearch?.cancel() request.naturalLanguageQuery = place request.region = region localSearch = MKLocalSearch(request: request) localSearch?.start { [weak self] response, error in let mapItems = response.mapItems //     MKMapItem } } // MARK: - CLLocationManagerDelegate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let lastLocation = locations.last else { return } let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5) region = MKCoordinateRegion(center: lastLocation.coordinate, span: span) } } 

Hasil
Lokasi perangkat saat ini - Madrid, penyedia Internet Vodafone ES

Dalam metode delagate didUpdateLocations, kami membuat MKCoordinateSpan . Jika saya memahami dokumentasi Apple dengan benar, maka semakin rendah nilai yang kami tetapkan Delta lintang / bujur, semakin sempit (dan lebih akurat) wilayah kami saat ini akan ditunjukkan, karena itu adalah semacam zoom pada koordinat kami saat ini di MapKit.
Setelah itu, memang, prioritas ekstradisi berubah dan menunjukkan kepada saya terutama tempat-tempat yang di sebelah saya.

Tetap hanya untuk membuat nama-nama dalam daftar lebih indah. Karena terkadang, beberapa properti CLPlacemark mungkin memiliki nama yang sama, pada akhirnya itu tidak akan terlihat sangat bagus: New York, New York, NY. Untuk melakukan ini, Anda perlu membuat Struktur terpisah, yang akan membentuk nama yang indah dalam daftar.

 import Foundation import MapKit struct Placemark { let location: String init(item: MKMapItem) { var locationString: String = "" if let name = item.name { locationString += "\(name)" } if let locality = item.placemark.locality, locality != item.name { locationString += ", \(locality)" } if let administrativeArea = item.placemark.administrativeArea, administrativeArea != item.placemark.locality { locationString += ", \(administrativeArea)" } if let country = item.placemark.country, country != item.name { locationString += ", \(country)" } location = locationString } } 

Kemudian, sudah menanggapi pencarian, kita dapat dengan mudah memetakan CLPlacemark ke dalam struktur yang dibuat dan meneruskannya ke daftar.

 localSearch?.start { [weak self] searchResponse, error in guard let items = searchResponse?.mapItems else { return } //  CLPlacemark    let placemarks = items.map { Placemark(item: $0) } } 

Sekarang hasilnya terlihat lebih elegan dan sudah dapat digunakan dalam proyek untuk menandai lokasi yang dikunjungi.

Salah satu kelemahan utama adalah bahwa Anda dapat menggunakan solusi ini hanya jika proyek dipertajam untuk iOS / Mac OS. Jika proyek ini melibatkan pengembangan untuk platform lain, saya akan merekomendasikan menggunakan solusi dari Google atau Facebook . Juga, tidak semua lokasi ditentukan secara ideal di semua wilayah.

Anda dapat melihat kode akhir proyek di repositori .

Source: https://habr.com/ru/post/id462465/


All Articles