ReverseGeocodeLocation завершает использование в viewDidLoad () swift4.1 - PullRequest
0 голосов
/ 07 мая 2018

Swift версия: 4.1

Здравствуйте, я немного больше, чем новичок в Swift. Работа в «приложении заказа по местоположению пользователя». Который я управляю именем пользователя "страна" и "город" с помощью reversegeocodelocation function перед тем, как пользователь отдаст заказ. И запишите эти значения в дочернюю базу данных Firebase в реальном времени.

моя структура данных похожа на

 -TR
   -Ankara
       -userID
           -Order(consist of user lat, user long, user mail, userOrder)

Ничего страшного, я сделал так, что пользователи могут заказывать и отменять его / ее заказы. Но я также хочу проверить, закрывают ли пользователи свой телефон и возвращают ли приложение, приложение должно проверить базу данных, и если текущий пользователь задал порядок uID, он должен изменить метку кнопки buttonToCancelState = true и изображение нашего талисмана. .

Вот так я получаю пользователя coord для заказа и "код страны" и "город" для имени структуры данных.

 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let location = locations [0]

    if let coord = manager.location?.coordinate {
        userLocation = coord

    }


    let geoCoder = CLGeocoder()
    geoCoder.reverseGeocodeLocation(location) {(placemark, error) in
        if error != nil {
            print("there is an error")
        } else {

        var placeMark: CLPlacemark?
        placeMark = placemark?[0]


        // City
        if let city = placeMark?.locality {
            self.userCity = city as String

        }

        // Country
        if let country = placeMark?.isoCountryCode {
            self.userCountry = country as String
            }
        }
    }
}

И я использую эти «страна» и «город» в «кнопке заказа», как в примере;

            orderHasBeenCalled = true
            buttonLabelText.text = "CANCEL/EDIT"
            imgView.image = UIImage(named: "...")
            let orderRequestDictionary: [String:Any] = ["..."]
            databaseREF.child(userCountry).child(userCity).child(userID!).setValue(orderRequestDictionary)

работает без сбоев, пользователь может отправить заказ, удалить его, даже если пользователь вышел из системы, тоже удалил (все коды не включены)

теперь проблема в том, что я хочу проверить, есть ли у пользователей заказ, когда viewDidLoad() загружается для этого, я использую

if let userID = FirebaseAuth.Auth.auth().currentUser?.uid {
        databaseRef.child(userCountry).child(userCity).queryOrdered(byChild: userID!).observe(.childAdded, with: { (snapshot) in
            self.OrderHasBeenCalled = true
            self.buttonLabelText.text = "CANCEL/EDIT"
            self.imgView.image = UIImage(named: "...")
            databaseRef.child(self.userCountry).child(self.userCity).removeAllObservers()
        })
   }

Теперь проблема в том, что я читаю в интернете reversegeocode асинхронный или что-то в этом роде, и, как кажется, он не готов, когда загрузка viewDidLoad (), "код для проверки наличия порядка" приводит к сбою приложения, поскольку оно находит нет значения для поиска имен у детей.

Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''

Чтобы использовать userCountry и userCity в кнопке заказа, я определяю их перед viewDidLoad ()

var userCountry = String()
var userCity = String()

Я пробовал много способов, но не понял, как мне получить завершение обратного геокода в viewdidload (). Я попытался viewDidAppear() слишком кстати, но он дает userCountry () и userCity () ноль тоже.

Надеюсь, мой вопрос ясен и легко понятен. Буду очень признателен, если ответы будут такими. Много занимался исследованиями в интернете, некоторые из них я пробовал, некоторые я не понимал или не знал, как я могу даже попробовать. Последнее, на что я надеюсь, это переполнение стека. Спасибо всем тем, чей добрый ответ на мой вопрос.

1 Ответ

0 голосов
/ 07 мая 2018

Я бы немного изменил подход. Работая с асинхронными функциями, вы должны избегать значений запроса синхронизации.

Есть несколько способов сделать вложенные вызовы из асинхронных функций, из вашего кода я пришел к этому подходу, адаптируясь к вашим потребностям, и он должен работать.

/////////attention the scope (must be above class declaration)
typealias CompletionGetAddress = (_ userCity : String?, _ userCountry: String?, _ success: Bool) -> Void
var userLocation = CLLocationCoordinate2D()
var locationManager = CLLocationManager()
//

class viewController: ... {
func viewDidLoad() {

    yourLocationManager.requestLocation()

    // you should implement some code to ensure your userLocation from your locationManager is not nil and a valid location

    if let userID = FirebaseAuth.Auth.auth().currentUser?.uid {
        if self.userCity != "" {
            databaseRef.child(userCountry).child(userCity).queryOrdered(byChild: userID!).observe(.childAdded, with: { (snapshot) in
                self.OrderHasBeenCalled = true
                self.buttonLabelText.text = "CANCEL/EDIT"
                self.imgView.image = UIImage(named: "...")
                databaseRef.child(self.userCountry).child(self.userCity).removeAllObservers()
            })
        } else {
            getAddress { (city, country, success) in
                if success {
                    self.userCity = city
                    self.userCountry = country
                    databaseRef.child(userCountry).child(userCity).queryOrdered(byChild: userID!).observe(.childAdded, with: { (snapshot) in
                        self.OrderHasBeenCalled = true
                        self.buttonLabelText.text = "CANCEL/EDIT"
                        self.imgView.image = UIImage(named: "...")
                        databaseRef.child(self.userCountry).child(self.userCity).removeAllObservers()
                    })
                }
            }           
        }
    }
} 
}


func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let location = locations [0]

    if let coord = manager.location?.coordinate {
        userLocation = coord /// attention here 

    }
}


func getAddress(completion: @escaping CompletionGetAddress) {
    let geoCoder = CLGeocoder()
    geoCoder.reverseGeocodeLocation(userLocation) {(placemark, error) in
        if error != nil {
            print("there is an error")
            completion(nil, nil, false)
        } else {
            var city: String = ""
            var country: String = ""
            var placeMark: CLPlacemark?
            placeMark = placemark?[0]
            // City
            if let c = placeMark?.locality {
                city = c
            }
            // Country
            if let c = placeMark?.isoCountryCode {
                country = c
            }
            completion(city, country, true)
        }
    }
}   
...