将对象从URLSession传递给ViewController

时间:2017-06-24 22:11:10

标签: ios swift urlsession

我正在尝试将一个名为detail的对象从一个名为RestManager.swift的swift文件传递给一个ViewController。该对象包含所有元素,但是当我在视图控制器中调用它时,它是空的。根据我在网上收集的内容,它可能与使用后台线程的URLSession有关

我的RestManager.swift看起来像这样。

class RestManager {


func reqDetails(id: Int) {
    // Create URL
    let id = String(id)
    let url = "https://website.example.com/"
    let url = URL(string: url + id)!

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

        if error != nil
        {
            print ("ERROR")
        }

        else
        {
            if let content = data
            {

                    let jsonData = JSON(data: content)

                    let id = jsonData["id"].intValue
                    let name = jsonData["title"]["rendered"].string!
                    let link = jsonData["link"].url!
                    let content = jsonData["content"]["rendered"].string!


                    // Create Object
                    let detail = Detail(id: id, name: name, content: content, thumbnailUrl: link)
                    self.details.append(detail)

            }
        }
    }
    task.resume()
}
}

我的视图控制器如下所示:

class DetailViewController: UIViewController {

var ListingID = Int()
let restManager = RestManager()

@IBOutlet weak var ContentLabel: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    restManager.reqDetails(id: ListingID)
    ContentLabel.text? = restManager.details[0].name // After running the app this index value is out of range.


}

..

}

3 个答案:

答案 0 :(得分:2)

使用close in函数传递这样的数据

func reqDetails(id: Int,completionHandler:@escaping (_ detilObject:Detail)->Void) {
    // Create URL
    let id = String(id)
    let url = "https://website.example.com/"
    let url = URL(string: url + id)!

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

        if error != nil
        {
            print ("ERROR")
        }

        else
        {
            if let content = data
            {

                    let jsonData = JSON(data: content)

                    let id = jsonData["id"].intValue
                    let name = jsonData["title"]["rendered"].string!
                    let link = jsonData["link"].url!
                    let content = jsonData["content"]["rendered"].string!


                    // Create Object
                    let detail = Detail(id: id, name: name, content: content, thumbnailUrl: link)
                    self.details.append(detail)
                    completionHandler(self.details)

            }
        }
    }
    task.resume()
}

并像这样调用你的函数。 “

restManager.reqDetails(id: ListingID , completionHandler: { (detail) in
                // here is your detail object
            })

答案 1 :(得分:0)

您已经纠正了您的问题是由于尝试立即阅读回复(因为它不太可能立即就绪)。当数据准备就绪(或发生错误)时,您需要一种方法来通知您的控制器(在主线程/队列上!)。

一个简单但不优雅的解决方案是将weak var controller: DetailViewController添加到RestManager(弱,因此它不会导致保留周期)init }(RestManager(controller: self))并在URL任务闭包中使用该引用来告诉控制器它已准备好或出错。

您应该使用通知或委托模式,以避免RestManagerDetailViewController的紧密耦合。

答案 2 :(得分:0)

您好我认为您刚刚遇到异步编程的典型陷阱。你所做的是在从URLSession返回之前询问任务的返回值。 您可以通过自己制作一个完成处理程序来解决这个问题,例如我从Darksky获取一些天气数据。 请注意,你甚至不需要为此创建一个类,只是一个函数。

PS注意我使用Alamofire,SwiftyJSON和Gloss,它使用REST接口大大降低了复杂性。这是Swift 3!

import Alamofire
import SwiftyJSON
import Gloss


typealias DarkSkyWeatherForecast = ( _ json : Gloss.JSON?,  _ error : Error?) -> Void


func getWeatherForcast( latitude:Double, longitude:Double,  completionHandler:@escaping DarkSkyWeatherForecast) -> Void {

    let urlString =  "https://api.darksky.net/forecast/"+darkSkyKey+"/"+String(latitude)+","+String(longitude)+"?units=si"

    Alamofire.request(urlString).responseJSON { (response) in
        if let resp = response.result.value {
            let json = JSON(resp)
            let glossJson = json.dictionaryObject
            completionHandler( glossJson, nil)
        }else{
            completionHandler( nil, response.error)
        }
    }
}

并且调用函数如下:

getWeatherForcast(latitude: lat, longitude: lon) { (jsonArg, error) in
            if error == nil{
                guard let weather = DarkSkyWeather(json: jsonArg!) else {
                    self.effectView.removeFromSuperview()
                    return
                }
                if let ambTemp = weather.currently?.temperature, let windspd = weather.currently?.windSpeed, let windDir = weather.currently?.windBearing{
                    self.effectView.removeFromSuperview()
                    self.ambTemperature.text = String(ambTemp)
                    self.windSpeed.text = String( windspd )
                    self.windDirection.text = String( windDir )
                    self.getSpeed()
                }
            }else{

               self.effectView.removeFromSuperview()
                let alert = UIAlertController(title: "Error", message: "Could not get weather forecast", preferredStyle: .alert)
                let okAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in
                    self.dismiss(animated: true, completion: nil)
                })
                alert.addAction(okAction)
                self.present(alert, animated: true, completion: nil)
            }
        }

注意,我只在完成处理程序完成后填充文本字段,并实际返回一些数据或错误。忽略“effectView”的东西,这是一个特殊的光标等待微调器: - )

而且要知道这些映射到json数据的结构可能会有所帮助:

//common struct for weather data
public struct WeatherDataStruct : Decodable{
    let time : Int?
    let summary : String?
    let icon : String?
    let precipIntensity : Double?
    let precipProbability : Double?
    let precipType : String?
    let temperature : Double?
    let apparentTemperature : Double?
    let dewPoint : Double?
    let humidity: Double?
    let windSpeed : Double?
    let windBearing : Int?
    let visibility : Double?
    let cloudCover : Double?
    let pressure : Double?
    let ozone : Double?

    public init?( json: JSON){
        self.time = "time" <~~ json
        self.summary = "summary" <~~ json
        self.icon = "icon" <~~ json
        self.precipIntensity = "precipIntensity" <~~ json
        self.precipProbability = "precipProbability" <~~ json
        self.precipType = "precipType" <~~ json
        self.temperature = "temperature" <~~ json
        self.apparentTemperature = "apparantTemperature" <~~ json
        self.dewPoint = "dewPoint" <~~ json
        self.humidity = "humidity" <~~ json
        self.windSpeed = "windSpeed" <~~ json
        self.windBearing = "windBearing" <~~ json
        self.visibility = "visibility" <~~ json
        self.cloudCover = "cloudCover" <~~ json
        self.pressure = "pressure" <~~ json
        self.ozone = "ozone" <~~ json
    }
}

//hourly weather struct
public struct HourlyStruct : Decodable{
    let summary : String?
    let icon : String?
    let data : [WeatherDataStruct]?

    public init?(json: JSON) {
        self.summary = "summary" <~~ json
        self.icon = "icon" <~~ json
        self.data = "data" <~~ json
    }
}

//total struct for the whole json answer from darksky weather
public struct DarkSkyWeather : Decodable{
    let latitude : Double?
    let longitude : Double?
    let timezone : String?
    let offset : Int?
    let currently : WeatherDataStruct?
    let hourly : HourlyStruct?

    public init?(json: JSON) {
        self.latitude = "latitude" <~~ json
        self.longitude = "longitude" <~~ json
        self.timezone = "timezone" <~~ json
        self.offset = "offset" <~~ json
        self.currently = "currently" <~~ json
        self.hourly = "hourly" <~~ json
    }
}