2017-10-06 32 views
0

您好,我正在尝试创建一个简单的应用程序,该应用程序从我的Web服务器获取注释,然后传播该地图他们。唯一的问题是,当我在30秒后调用函数bob从另一个位置获得新注释时,它给了我上面的错误,我尝试使用DispatchQueue.main.async来解决这个问题无济于事。任何帮助表示赞赏。即使在使用DispatchQueue的情况下,获得“在从主线程访问引擎后,从后台线程修改自动布局引擎”

这里是有问题的功能

// this is the test to see if it can add a new annotation after 30 seconds 
if bob == 30{ 

    let user_lat_temp = 26.7709 
    let user_lng_temp = -80.1067 

    DispatchQueue.main.async() { 
     // Do stuff to UI 
     self.GetAnnotations(lat: user_lat_temp, lng: user_lng_temp) 
    } 

    // reset it to see if it breaks 
    bob = 0 
    } 
    bob = bob + 1 
    print("bob: ", bob) 
} 

下面是完整的代码

import UIKit 
import MapKit 
import CoreLocation 

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate { 



    @IBOutlet weak var mapView: MKMapView! 
    let access_token = "" 
    let manager = CLLocationManager() 
    var firstTime = 1 
    var user_lat = 0.0 
    var user_lng = 0.0 

    var bob = 0 

    override func viewDidLoad() { 

     super.viewDidLoad() 

     manager.delegate = self 
     manager.desiredAccuracy = kCLLocationAccuracyBest 
     manager.requestWhenInUseAuthorization() 

     manager.startUpdatingLocation() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 


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

     let userLocation = locations[0] 


     user_lat = userLocation.coordinate.latitude 
     user_lng = userLocation.coordinate.longitude 

     self.mapView.showsUserLocation = true 

     if firstTime == 1{ 

      GetAnnotations(lat: user_lat, lng: user_lng) 

      firstTime = 0 
     } 


     // this is the test to see if it can add a new annotation after 30 seconds 
    if bob == 30{ 
     let user_lat_temp = 26.7709 
     let user_lng_temp = -80.1067 

     DispatchQueue.main.async() { 
      // Do stuff to UI 
      self.GetAnnotations(lat: user_lat_temp, lng: user_lng_temp) 
     } 

     // reset it to see if it breaks 
     bob = 0 
     } 
     bob = bob + 1 
     print("bob: ", bob) 
    } 

    func GetAnnotations(lat: Double, lng: Double){ 

     guard let url = URL(string: "http://192.168.1.10:7888/api/?controller=location&action=get_locations") else {return} 

     var request = URLRequest(url: url) 

     request.httpMethod = "POST" 

     let postString = "access_token=\(access_token)&lat=\(lat)&lng=\(lng)"; 

     request.httpBody = postString.data(using: String.Encoding.utf8) 

     URLSession.shared.dataTask(with: request) { (data, response, err) in 

      if let error = err { 
       print("the server is not responding \(error)") 
      } 

      if let response = response { 

       // if the user has a bad access token or is logged out 
       if let httpResponse = response as? HTTPURLResponse { 
        if httpResponse.statusCode == 401{ 
         print("bad access token") 
         return 
        } 
       }else{ 
        print("the server is not responding") 
      } 
      print(response) 




      guard let data = data else { return } 

      // parse the json for the locations 
      do { 
       let mapJSON = try JSONDecoder().decode(parseJsonLocations.self, from: data) 
       let user_id = mapJSON.user_info.user_id 

       print(user_id) 
       print(mapJSON.locations.count) 

      // do map 
       let distanceSpan:CLLocationDegrees = 10000 
       let userLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng) 
       self.mapView.setRegion(MKCoordinateRegionMakeWithDistance(userLocation, distanceSpan, distanceSpan), animated: true) 
       self.mapView.delegate = self 

       var i = 0 

       while i < mapJSON.locations.count { 

        let location_id = mapJSON.locations[i].location_id 
        let location_name = mapJSON.locations[i].location_name 
        let location_lat = mapJSON.locations[i].lat 
        let location_lng = mapJSON.locations[i].lng 

        let locationsLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location_lat, location_lng) 

        let subtitle = "location_id: \(location_id)" 

        let userAnnotation = Annotation(title: location_name, subtitle: subtitle, coordinate: locationsLocation) 

        self.mapView.addAnnotation(userAnnotation) 

        i = i + 1 

       } 

      } catch { 
       print("error trying to convert data to JSON") 
       print(error) 
      } 





     } 
     }.resume() 
    } 


} 

回答

1

你有正确的想法;显式调度主队列上的UI更新,不幸的是你发送了错误的函数。

GetAnnotations(其中,按照惯例应该是getAnnotations)使得通过URLSessionDataTask异步网络电话,与导致完成处理程序返回。通过这些网络操作,完成处理程序很可能不会在主队列中调用,而这种情况就是这种情况。

由于完成处理程序没有在主队列上执行并且您更新了UI,因此会收到错误消息。

你需要派遣主队列

例如那些UI操作:

guard let data = data else { return } 

DispatchQueue.main.async { 
     // parse the json for the locations 
     do { 
      let mapJSON = try JSONDecoder().decode(parseJsonLocations.self, from: data) 
      let user_id = mapJSON.user_info.user_id 

      print(user_id) 
      print(mapJSON.locations.count) 

     // do map 
      let distanceSpan:CLLocationDegrees = 10000 
      let userLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng) 
      self.mapView.setRegion(MKCoordinateRegionMakeWithDistance(userLocation, distanceSpan, distanceSpan), animated: true) 
      self.mapView.delegate = self 

      var i = 0 

      while i < mapJSON.locations.count { 

       let location_id = mapJSON.locations[i].location_id 
       let location_name = mapJSON.locations[i].location_name 
       let location_lat = mapJSON.locations[i].lat 
       let location_lng = mapJSON.locations[i].lng 

       let locationsLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location_lat, location_lng) 

       let subtitle = "location_id: \(location_id)" 

       let userAnnotation = Annotation(title: location_name, subtitle: subtitle, coordinate: locationsLocation) 

       self.mapView.addAnnotation(userAnnotation) 

       i = i + 1 

      } 

     } catch { 
      print("error trying to convert data to JSON") 
      print(error) 
     } 
} 

在外景经理委托调用的情况下,该文件规定:

的您的委托对象的方法从您启动相应位置服务的线程中调用。该线程本身必须有一个活动的运行循环,就像在应用程序的主线程中找到的一样。

所以,只要你从主队列称为startUpdatingLocation,你委托的回调将在主队列

2

有很多的其他地方,你不关注什么线程你可能的问题开启。

你是说

if firstTime == 1 { 
    GetAnnotations(// ... 

不确保你在主线程上。

,然后里面GetAnnotations,你说

self.mapView.setRegion 
// ... and all that follows ... 

不确保你在主线程上。

我并不是说在那些时刻你不在主线上,但是没有理由认为你是。你应该检查并整理出来。

+0

所以你说,我要补充的DispatchQueue.main.async的getAnnotations函数内和firstTime? – Julian

相关问题