2017-01-17 5 views
0

CLLocationを使用してPageViewControllerでのユーザーの場所を特定し、返された場所をlocationManager(_:didUpdateLocations:)からRealmデータベースに書き込んだ後、PageViewControllerのコンテンツページのMy関数でRealmを使用する必要があります。コンテンツページは別のソースファイル(ビューコントローラ)。そう:すぐにRealmでNSOperationのCLLocationデリゲートを使用する方法は?

まず、位置決め成功、

第二は、第二工程の成功の後、コンテンツページ内の関数を呼び出す、レルムの位置、

第三のを書き込みます。

そして、私は上記の手順を制御するための依存関係が、デリゲートの機能locationManager(_:didUpdateLocations:)でNSOperationQueueを使用するには呼ばず、コードはレルムデータを読みたい時にアプリのクラッシュを引き起こす決して思わ:

の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

実際にRealmにデータを書き込むコードはありません。いつ、どのように正確にやっていますか?クラッシュについては、変数 '' nil''( '' locality''または '' subLocality'')を想定している変数のように聞こえますが、実際には 'nil'で、例外を発生させてアンラッピングします。これは、あなたが戻ってあなたのロジックをより詳細に調べる必要があるかもしれないことを意味するかもしれません。 – TiM

+0

申し訳ありませんが、Realmへの書き込みデータは 'locationManager(_:didUpdateLocations:)'にあります(plsは問題の更新された説明を参照してください)。また、アプリがクラッシュする理由は、 'locality'と' subLocality'が 'nil'であるためです。しかし、どのようにして 'locationManager(_:didUpdateLocations:)'が最初に呼び出され、次にRealmにデータが書き込まれ、最後にcontentViewControllerで 'updateWether'メソッドが呼び出されるようにコードを制御することができますか? – stephen

+0

@TiMでも、私はOperationqueue依存関係で 'self.locationManager.requestLocation()'を制御して最初に呼び出すことができますが、デリゲートが終了していない、あるいは呼び出されているように見えます。 Operationqueue依存関係の 'locationManager(_:didUpdateLocations:)'を制御することは可能ですか?非常にあなたの助けに感謝! – stephen

答えて

0

さて、ロジックを調べたところ、何が起きているのかが分かりました。

操作キュー(特にメインキュー)にself.locationManager.requestLocation()を置くことは意味がありません。 According to the documentationrequestLocation()が直ちに戻り、ロケーションサービスに対する実際の要求は、システムによって制御されるバックグラウンドスレッドで行われます。

ロケーションサービスがデバイスの場所を決定すると、デリゲートメソッドdidUpdateLocationsが呼び出されますが、これは簡単に数秒かかることがあります。

一方、ContentViewControllerを即座にロードしています。これは、ロケーションサービスがデリゲートを呼び出してRealmに初めてデータを挿入する前に、updateWeather()をトリガーしています。

これは完全に正常なロジックモデルです。何らかの種類のローディングスピナーを使用してView Controllerを表示し、Location Servicesが完了した後にそれを更新するのが理にかなっています。したがって、Realmファイルが空であってもupdateWeather()が機能していることを確認し、Realmファイルに実際にデータがあるとUIを更新するロジックも組み込む必要があります。

最も簡単なことは、localitysubLocalitynilではないことを確認し、そうでないときにのみクエリを実行することです。

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()を呼び出す必要があります。

関連する問題