简体   繁体   English

iOS Swift如何在需要返回值的函数中等待异步任务

[英]iOS swift how can I await an async task inside a function that needs a return value

I am using swift 3.0 and have created a function that returns an Array of Integers. 我正在使用swift 3.0,并创建了一个返回整数数组的函数。 The arrays of Integers are very specific and they are gotten from a database therefore the HTTP call is asynchronous . 整数数组非常具体,它们是从数据库中获取的,因此HTTP调用是异步的。 This is a function because I use it in 3 different controllers so it makes sense to write it once . 这是一个功能,因为我在3个不同的控制器中使用了它,因此一次编写它很有意义。 My problem is that the Async code is returned after the return statement at the bottom therefore it is returning nil . 我的问题是异步代码在底部的return语句后返回,因此它返回nil。 I have tried the example here Waiting until the task finishes however it is not working mainly because I need to return the value . 我在这里尝试过该示例, 直到任务完成为止,但是它不能正常工作主要是因为我需要返回值。 This is my code 这是我的代码

func ColorSwitch(label: [UILabel]) -> [Int] {

    for (index, _) in label.enumerated() {
       label[index].isHidden = true
    }

    // I need the value of this variable in the return
    // statement after the async is done
    var placeArea_id = [Int]()

    let urll:URL = URL(string:ConnectionString+"url")!

    let sessionn = URLSession.shared
    var requestt = URLRequest(url: urll)
    requestt.httpMethod = "POST"


    let group = DispatchGroup()
    group.enter()

    let parameterr = "http parameters"
    requestt.httpBody = parameterr.data(using: String.Encoding.utf8)
    let task =   sessionn.dataTask(with:requestt, completionHandler: {(data, response, error) in
        if error != nil {
            print("check check error")
        } else {
            do {

                let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
                DispatchQueue.main.async {

                    if let Profiles = parsedData?["Results"] as? [AnyObject] {
                        if placeArea_id.count >= 0 {
                            placeArea_id = [Int]()   
                        }

                        for Profiles in Profiles {

                            if let pictureS = Profiles["id"] as? Int {
                                placeArea_id.append(pictureS)
                            }
                        }
                    }
                    group.leave()
                }

            } catch let error as NSError {
                print(error)

            }
        }
    })
    task.resume()


    group.notify(queue: .main) {
   // This is getting the value however can't return it here since it 
   // expects type Void
    print(placeArea_id)

    }
   // this is nil
    return placeArea_id

}

I already checked and the values are returning inside the async code now just need to return it any suggestions would be great . 我已经检查过了,这些值正在异步代码中返回,现在只需要返回它,任何建议都将很棒。

You will want to use closures for this, or change your function to be synchronous. 您将为此使用闭包,或将函数更改为同步。

func ColorSwitch(label: [UILabel], completion:@escaping ([Int])->Void) {
    completion([1,2,3,4]) // when you want to return
}

ColorSwitch(label: [UILabel()]) { (output) in
    // output is the array of ints
    print("output: \(output)")
}

Here's a pretty good blog about closures http://goshdarnclosuresyntax.com/ 这是一个关于闭包的不错的博客http://goshdarnclosuresyntax.com/

You can't really have your function return a value from an asynchronous operation within that function. 您实际上无法让函数从该函数内的异步操作返回值。 That would defeat the purpose of asynchronicity. 那会破坏异步的目的。 In order to pass that data back outside of your ColorSwitch(label:) function, you'll need to also have it accept a closure that will be called on completion, which accepts an [Int] as a parameter. 为了将数据传递回ColorSwitch(label:)函数之外,您还需要使其接受一个闭包,闭包将在完成时被调用,该闭包接受一个[Int]作为参数。 Your method declaration will need to look something like this: 您的方法声明将需要如下所示:

func ColorSwitch(label: [UILabel], completion: @escaping ([Int]) -> Void) -> Void {

    for (index, _) in label.enumerated() {
        label[index].isHidden = true
    }

    var placeArea_id = [Int]()

    let urll:URL = URL(string:ConnectionString+"url")!

    let sessionn = URLSession.shared
    var requestt = URLRequest(url: urll)
    requestt.httpMethod = "POST"


    let group = DispatchGroup()
    group.enter()

    let parameterr = "http parameters"
    requestt.httpBody = parameterr.data(using: String.Encoding.utf8)
    let task =   sessionn.dataTask(with:requestt, completionHandler: {(data, response, error) in
        if error != nil {
            print("check check error")
        } else {
            do {

                let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
                DispatchQueue.main.async {

                    if let Profiles = parsedData?["Results"] as? [AnyObject] {
                        if placeArea_id.count >= 0 {
                            placeArea_id = [Int]()
                        }

                        for Profiles in Profiles {

                            if let pictureS = Profiles["id"] as? Int {
                                placeArea_id.append(pictureS)
                            }

                        }
                    }
                    group.leave()
                    completion(placeArea_id) // This is effectively your "return"
                }

            } catch let error as NSError {
                print(error)

            }

        }

    })
    task.resume()
}

Later on, you can call it like this: 稍后,您可以这样称呼它:

ColorSwitch(label: []) { (ids: [Int]) in
    print(ids)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM