2016-11-07 9 views
0

私は、バックグラウンドでオブジェクトをフェッチし、それらの場所のデータを使って地図スナップショットを生成するはずのアプリを持っています。当然私はMKMapSnapshotterを試しました。バックグラウンドでのMKMapSnapshotterの使用方法を教えてください。

それはそうのようなメインスレッドから呼び出されたときに、このツールだけで動作するように思われること(黒マップのスナップショットについて混乱しているの週後)判明:

dispatch_async(dispatch_get_main_queue(), ^{ 
    MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options]; 
     [snapshotter startWithQueue:dispatch_get_main_queue() completionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { 
     //Use image here. Image would be completely black if not for the first line of code specifying main thread. 
    }]; 
}); 

は、このフレームワークのバグですか?

問題:これは、アプリケーションがフォアグラウンドにあるときにのみ実行されます。

答えて

1

これは、複数のズームレベルのマップタイルセットをダウンロードするための呼び出しがたくさんあるので、私が取り組んでいるアプリにとっては少し複雑だったので、以下のコードは必要以上に複雑ですそのキューはスナップショット作成のために機能します)。たとえば、ディスパッチセマフォーを使用すると、数百から数千もの同時スナップショットをキューに入れないようにする必要があります。これにより、スレッドでキャプチャされているスナップショットが約25個に制限されます。

また、私はSwift 3でこれをやっていますので、あなたに問題を提示しながらGCDに変更を加えることができます。

ロジックは、メインキューがブロック解除されたままで、UIがアクティブのままである間に、すべてのリクエストをprocessQueueで開始することです。次に、最大25個のリクエストがいつでもセマフォゲートを通過するので、snapshotter.startコールを介してsnapshotQueueに入ります。 1つのスナップショットが終了すると、もう1つはprocessQueueが空になるまで開始されます。

unowned let myself = self // Avoid captures in closure 

let processQueue = DispatchQueue(label: "processQueue", qos: .userInitiated) 
let snapshotQueue = DispatchQueue(label: "snapshotQueue") 
var getSnapshotter = DispatchSemaphore(value: 25) 

processQueue.async 
     { 
      var centerpoint = CLLocationCoordinate2D() 
      centerpoint.latitude = (topRight.latitude + bottomLeft.latitude)/2.0 
      centerpoint.longitude = (topRight.longitude + bottomLeft.longitude)/2.0 
      let latitudeDelta = abs(topRight.latitude - bottomLeft.latitude) 
      let longitudeDelta = abs(topRight.longitude - bottomLeft.longitude) 
      let mapSpan = MKCoordinateSpanMake(latitudeDelta, longitudeDelta) 

      var mapRegion = MKCoordinateRegion() 
      mapRegion.center = centerpoint 
      mapRegion.span = mapSpan 

      let options = MKMapSnapshotOptions() 
      options.region = mapRegion 
      options.mapType = .standard    
      options.scale = 1.0 
      options.size = CGSize(width: 256, height: 256) 

      myself.getSnapshotter.wait()  // Limit the number of concurrent snapshotters since we could invoke very many 

      let snapshotter = MKMapSnapshotter(options: options) 

      snapshotter.start(with: myself.snapshotQueue, completionHandler: {snapshot, error in 
       if error == nil 
       { 
        self.saveTile(path: path, tile: snapshot!.image, z: z, x: x, y: y) 
        // saveTile writes the image out to a file in the mapOverlay file scheme 
       } else { 
        print("Error Creating Map Tile: ", error!) 
       } 
       if myself.getSnapshotter.signal() == 0 
       { 
        // show status as completed (though could be up to 20 snapshots finishing, won't take long at this point 
       } 
      }) 
    } 

これは、UIをブロックすることなく、7ズームレベルオフライン地図画像セットを構築するために5Kのスナップショットを取得して私の作品、私はコードでかなり快適です。

+0

フォアグラウンドにする必要があるので、私は[UIApplication.shared.isIdleTimerDisabled = true]というコマンドを使用します。完了したら、必ずfalseに設定してください。 –

+0

うわー、印象的ですね。私はこのような高度なキューイングに精通していません。この解決策のいくつかの形式を試してみてください。 – TealShift

+0

私はApple Watchからトレーニングデータを引き出しているので、残念ながらフォアグラウンドが必要です.BG処理を中止する唯一の方法はこのダム機能です。 :/ – TealShift

関連する問題