2017-04-04 3 views
0

私はここで私の知恵の終わりです。私は考えることができるすべてを試しましたが、これを動作させることはできません。URLSession(Swift3)のデータに基づいてアニメーションを実行するのに役立つ必要があります

私はここでやろうとしているような気がしますが、シンプルでなければなりませんが、スウィフトはそれをばかげて難しくしています。

最終的に、私がしたいのは、Webスクリプト(浮動小数点数を返します)から単一のデータを取得し、その浮動小数点数を使用してUIViewをアニメーション化することだけです。

わかりやすくするために、Webスクリプトは「50.0」を返すと仮定します。私はその数値を取得し、UIViewを0pxから50pxの高さにアニメーション化したいと考えています。

私は、非同期タスクからデータを取得することはできず、基本的にはそのデータをクロージャの内部で実行する必要があるタスクを実行する必要があることを読んでいます。しかし、閉鎖の中で私のアニメーションを動かそうとすると、Xcodeは手首を叩き、別のスレッドでAutoLayoutのプロパティを修正しようとしていると私に伝えます。だから私は何をしなければならないのですか?以下は

私ができるよう最善のようにコメントし、私のコードです:開始するには

、私は紫色の背景を持っている私のViewControllerでのUIViewを持っています。このUIViewには緑色のサブビューが追加されており、Webスクリプトの戻り値に基づいて垂直方向に拡大し、効果的に「メーター」(画像参照)を作成します。

enter image description here

//This variable is passed in from the Segue & will eventually be passed to the web script, so it knows which ID to pull the data from. 
var deviceID: String = "" 


//This is a programmatically created UIView that will be added as a subview to the UIView that has been dragged to the View Controller. Based on the image, this will eventually be the "green" rectangle that you see. 
let oilReading = UIView() 


//This is the outlet for the UIView that I dragged into the ViewController. Based on the image, this is the purple background. 
@IBOutlet weak var tankRep: UIView! 


override func viewDidLoad() { 
    super.viewDidLoad() 
} 


override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 


    //This block styles the purple block to give it rounded corners & a shadow. 
    tankRep.layer.cornerRadius = 8 
    tankRep.clipsToBounds = true 
    tankRep.layer.masksToBounds = false; 
    tankRep.layer.shadowOffset = CGSize(width: 5.0, height: 5.0); 
    tankRep.layer.shadowRadius = 8; 
    tankRep.layer.shadowOpacity = 0.25; 



    //These lines set some default styles for the green block (color & position) 
    oilReading.frame = CGRect(x: tankRep.bounds.origin.x, y: CGFloat(tankRep.bounds.height), width: CGFloat(100), height: CGFloat(0)) 
    oilReading.backgroundColor = UIColor(red: 56/255, green: 221/255, blue: 166/255, alpha: 1.0) 


    //These lines create a mask for the green block so the corners are rounded. 
    let maskPath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: Int(oilMeterHeight)), byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 8.0, height: 8.0)) 
    let maskLayer = CAShapeLayer() 
    maskLayer.path = maskPath.cgPath 
    self.oilReading.layer.mask = maskLayer 

    //Add the green block as a subview to the purple block 
    tankRep.addSubview(oilReading) 
    tankRep.sendSubview(toBack: oilReading) 

    //================================================================ 
    // THIS NEEDS TO RUN BASED ON THE VALUE OF THE WEB SCRIPT 
    // Where I am referencing "oilMeterHeight" is what would ultimately come from the web script 
    //================================================================ 

    UIView.transition(with: oilReading, duration: 1.0, animations: {self.oilReading.frame = CGRect(x: self.tankRep.bounds.origin.x, y: CGFloat(self.tankRep.bounds.height - CGFloat(oilMeterHeight)), width: 100, height: CGFloat(oilMeterHeight))}, completion: nil) 



    //This calls the function that runs the webscript 
    getMeterHeight(deviceID: deviceID) 
} 


private func getMeterHeight(deviceID: String) { 

    guard let URL = URL(string: "http://www.mywebsite.com/getLatestReading.php") else {return} 
    let request = NSMutableURLRequest(url: URL) 

    request.httpMethod = "POST" 

    request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 

    let bodyObject: [String: String] = [ 
     "deviceID": deviceID 
    ] 

    request.httpBody = try! JSONSerialization.data(withJSONObject: bodyObject, options: []) 
    var responseString: NSString = "" 

    let task = URLSession.shared.dataTask(with: request as URLRequest) { 
     data, response, error in 

     if (error == nil) { 
      responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! 

      //This is the value that I need to get out of this unescapable black hole 
      let oilMeterHeight = 175 * responseString.doubleValue; 

      //Alternately, if I cannot get the previously set value out of this method, then I would like to run the following code - which in its current state does not work... 
      //UIView.transition(with: self.oilReading, duration: 1.0, animations: {self.oilReading.frame = CGRect(x: self.tankRep.bounds.origin.x, y: CGFloat(self.tankRep.bounds.height - CGFloat(oilMeterHeight)), width: 100, height: CGFloat(oilMeterHeight))}, completion: nil) 
     } else { 
      // Failure 
      print("URL Session Task Failed: %@", error!.localizedDescription); 
     } 
    } 

    task.resume() 
} 

答えて

1

iOS版では、バックグラウンドスレッドでUIを更新することはできません。 UIを更新するには、このようなメインスレッドでコードを書く:あなたのケースで

DispatchQueue.main.async{ 
     //update your UI here 
    } 

を、値でビューをアニメーション化するために、Webサービスの応答に入る、ちょうどresult.Ifを取得した後、このブロックを書きますすべては、あなたのgetMeterHeightメソッドは次のようになり、あなたのAPI呼び出しを持つ権利である:

private func getMeterHeight(deviceID: String) { 

    guard let URL = URL(string: "http://www.mywebsite.com/getLatestReading.php") else {return} 
    let request = NSMutableURLRequest(url: URL) 

    request.httpMethod = "POST" 

    request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 

    let bodyObject: [String: String] = [ 
    "deviceID": deviceID 
    ] 

    request.httpBody = try! JSONSerialization.data(withJSONObject: bodyObject, options: []) 
    var responseString: NSString = "" 

    let task = URLSession.shared.dataTask(with: request as URLRequest) { 
    data, response, error in 

    if (error == nil) { 
     responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)! 

     //This is the value that I need to get out of this unescapable black hole 
     let oilMeterHeight = 175 * responseString.doubleValue; 

     DispatchQueue.main.async{ 
      //update your UI here 
      UIView.transition(with: self.oilReading, duration: 1.0, animations: {self.oilReading.frame = CGRect(x: self.tankRep.bounds.origin.x, y: CGFloat(self.tankRep.bounds.height - CGFloat(oilMeterHeight)), width: 100, height: CGFloat(oilMeterHeight))}, completion: nil) 

     } 
    } else { 
     // Failure 
     print("URL Session Task Failed: %@", error!.localizedDescription); 
    } 
} 

task.resume() 
    } 
+0

これはトリックをしました。大変ありがとうございました!素晴らしい。 –

+0

あなたの歓迎@John Hubler –

関連する問題