2017-01-17 4 views
0

Я использую CLLocation для определения места пользователя в PageViewController и вам нужно использовать возвращаемое местоположение от locationManager(_:didUpdateLocations:), записывая в базу данных Realm, а затем используя Realm в моей функции на странице контента PageViewController. Страница содержимого реализована в отдельный исходный файл (контроллер просмотра). так:Как использовать делегаты CLLocation в NSOperation с Realm in swift?

первых, размещение успех,

второй, напишите место в области,

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

И я использую NSOperationQueue с зависимостями для контроля над шагами, но функция делегат locationManager(_:didUpdateLocations:) кажется, никогда не называет, и вызвать сбой приложения, когда код хочет прочитать данные области действия:

Pls увидеть следующий мой код:

PageViewController

class PageViewController: UIPageViewController { 
    static var isFirstLaunch: Bool = true 
    let locationManager: CLLocationManager = CLLocationManager() 

override func viewDidLoad() { 
    super.viewDidLoad() 

    locationManager.delegate = self 
    locationManager.requestWhenInUseAuthorization() 
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters 
    locationManager.distanceFilter = 3000 

    launchQueue = OperationQueue() 

    let locationOperation = BlockOperation { 
     OperationQueue.main.addOperation { 
      self.locationManager.requestLocation() 
     } 

    } 
    locationOperation.completionBlock = { 
     print("locationOperation finished, finished:\(locationOperation.isFinished)") //"locationOperation finished, finished:true" in console 
    } 

    let firstLaunchOperation = BlockOperation { 
     PageViewController.isFirstLaunch = false 
    } 
    firstLaunchOperation.completionBlock = { 
     print("firstLaunchOperation finished, finished:\(firstLaunchOperation.isFinished)") //"firstLaunchOperation finished, finished:true" in console 
    } 

    firstLaunchOperation.addDependency(locationOperation) 

    launchQueue.addOperation(locationOperation) 
    launchQueue.addOperation(firstLaunchOperation) 
    } 

ContentViewController (в отдельном исходном файле)

class ContentViewController: UIViewController { 
    let defaultRealm = try! Realm() 
    let config = Realm.Configuration(fileURL: Bundle.main.url(forResource: "areaID", withExtension: "realm"), readOnly: true) 

override func viewDidLoad() { 
    super.viewDidLoad() 

    UISetup() 
    autolayoutView() 

    if !PageViewController.isFirstLaunch { 
      upateWeather() 
    } 
} 

func upateWeather() { 
    let userArea = defaultRealm.objects(UserArea.self) 
    let place = userArea.first?.areas 
    let locality = place?[currentPage].locality 
    let subLocality = place?[currentPage].subLocality 
    let areaIDRealm = try! Realm(configuration: config) 

    let results = areaIDRealm.objects(RealmObject.self).filter("locality = '\(locality!)' AND subLocality = '\(subLocality!)'") 
    //Crashed here! fatal error: unexpectedly found nil while unwrapping an Optional value. I opened the realm, and no locality and subLocality write in the Realm. 

} 

} 

CLLocationManagerDelegate

extension PageViewController: CLLocationManagerDelegate { 

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 
let currentLocation: CLLocation = locations[0] 
let geocoder: CLGeocoder = CLGeocoder() 

if currentLocation.horizontalAccuracy > 0 { 
    geocoder.reverseGeocodeLocation(currentLocation, completionHandler: {(placeMarks, error) in 
     if error == nil { 
      guard let placemark = placeMarks!.first else { return } 

      let userArea = self.defaultRealm.objects(UserArea.self) 

      func locationToRealm(place: String, subPlace: String) { 
       if let gpsLocation = userArea.first?.areas.first { 
        self.defaultRealm.beginWrite() 
        gpsLocation.locality = place 
        gpsLocation.subLocality = subPlace 
        try! self.defaultRealm.commitWrite() 
       } else { 
        try! self.defaultRealm.write { 
         self.defaultRealm.create(UserArea.self, value: [[["locality": place, "subLocality": subPlace]]]) 
        } 
       } 
      } 

      if let place: String = placemark.locality { 
       if let subPlace: String = placemark.subLocality { 
        locationToRealm(place: place, subPlace: subPlace) 
       } else { 
        locationToRealm(place: place, subPlace: "---") 
       } 
      } else { 
       if let subPlace: String = placemark.subLocality { 
        locationToRealm(place: "---", subPlace: subPlace) 
       } 
      } 
     } 
    }) 
} 
} 

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {......} 

} 

Как я могу использовать NSOperationQueue контролировать код, сделать их шаг за шагом! Огромное спасибо за помощь!

+0

Я не вижу никакого кода для фактической записи данных в Царство. Когда и как вы это делаете? Что касается сбоя, это звучит как переменная, которую вы предполагаете не-'nil' (я предполагаю, что« locality »или' subLocality') на самом деле является «nil», вызывая и разворачивая исключение. Это может означать, что вам нужно вернуться назад и изучить свою логику более подробно. – TiM

+0

Извините, записи данных в Realm находятся в 'locationManager (_: didUpdateLocations:)' (PLS см. Обновленное описание). Я также думаю, что причина, по которой приложение разбилась, состоит в том, что «locality» и «subLocality» являются «nil». Но как я могу контролировать свой код, чтобы сначала вызывать 'locationManager (_: didUpdateLocations:)', а затем записывать данные в Realm, а затем, наконец, вызвать метод «updateWether» в contentViewController? – stephen

+0

@TiM даже я могу управлять 'self.locationManager.requestLocation()' в Operationqueue, чтобы заставить его вызываться первым, но, похоже, делегат не закончен или даже не вызван. Можно ли управлять 'locationManager (_: didUpdateLocations:)' в зависимости от операции? Очень ценю вашу помощь! – stephen

ответ

0

Хорошо, я изучил логику, и я думаю, что вижу, что происходит.

Нет смысла размещать self.locationManager.requestLocation() в операционной очереди (особенно в основной очереди). According to the documentation, requestLocation() немедленно возвращается, и фактический запрос к службам местоположения происходит в фоновом потоке, управляемом системой.

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

В то же время вы сразу же загружаете ContentViewController, и это запускает updateWeather(), прежде чем службы определения местоположения имели возможность вызвать делегата и вставить данные в Realm в первый раз.

Это совершенно нормальная логическая модель. Было бы целесообразно показать контроллеру вида какой-то загрузочный счетчик и впоследствии обновить его после завершения службы геолокации. Таким образом, вы должны убедиться, что updateWeather() может работать, даже если файл Realm пуст, и вы должны также включить логику для обновления пользовательского интерфейса, как только у файла Realm действительно есть данные.

Проще всего сделать, чтобы проверить, что locality и subLocality не являются nil и выполняют только запрос, если они не являются.

func upateWeather() { 
    let userArea = defaultRealm.objects(UserArea.self) 
    let place = userArea.first?.areas 
    let locality = place?[currentPage].locality 
    let subLocality = place?[currentPage].subLocality 
    let areaIDRealm = try! Realm(configuration: config) 

    // Only proceed if the Realm query variables aren't nil 
    guard let locality = locality, subLocality = subLocality else { 
     return 
    } 

    let results = areaIDRealm.objects(RealmObject.self).filter("locality = '\(locality!)' AND subLocality = '\(subLocality!)'") 
    //Crashed here! fatal error: unexpectedly found nil while unwrapping an Optional value. I opened the realm, and no locality and subLocality write in the Realm. 

} 

После этого Вам нужно позвонить updateWeather() снова после того, как делегат завершил запись в Realm, чтобы попробовать еще раз.

Смежные вопросы