闭包返回值(先前为completionBlock)

时间:2014-06-04 07:04:14

标签: swift ios8

我希望在长期操作完成后返回一些值。 但此外,我想分裂逻辑和gui。

例如;我有两个班级

  1. SomeServices.swift,其方法名为“getDataFromService ...”
  2. MyTableViewController.swift将显示“getDataFromService”
  3. 的结果

    所以,以前在Objective-C中我只是在SomeServices中添加一个方法:

    (void)getDataFromService:(void (^)(NSArray *, NSError *))completionBlock{ ...... }
    

    在这个方法中,我刚刚调用completionBlock(myData, myError)将我的值返回到tableviewcontroller。

    我必须在SomeServices.swift中定义的等效闭包是什么以及如何在MyTableViewController中调用它?

    我知道如何调用这样的简单闭包:

       ....({
                responseData, error  in
                if(!error){
                    //Do something
                }
            })
    

    但我没有任何想法如何定义一个与completionBlock等效的闭包。

    任何帮助将不胜感激

3 个答案:

答案 0 :(得分:14)

关闭的好处是,你可以传递你想要的一切。方法或功能 - 它并不重要。

您可以在参数中传递一个函数,然后调用它。

func someFunctionThatTakesAClosure(completionClosure: () -> ()) {
    // function body goes here
    if(error = false) {
       completionClosure()
    }

}

//Call it
someFunctionThatTakesAClosure({
    //Completions Stuff
    println("someFunctionThatTakesAClosure")
});

摘自:Apple Inc.“The Swift Programming Language。”iBooks。 https://itun.es/ch/jEUH0.l

答案 1 :(得分:3)

答案在语言指南中:

假设您要返回一个String。这是语法

({(responseData: DataClass, error: ErrorClass) -> String in
//do stuff - calculations etc..
return calculatedString
})

这是一个示例,它接受两个字符串并连接它们,并返回结果:

let sumStrings = ({(first: String, second: String) -> String in
    return first + " " + second
})

然后您可以执行以下操作:

sumStrings("Hello","Swift")             // "Hello Swift"

答案 2 :(得分:1)

以下是我使用单例ServiceManager实现此目的的方法。

class ServiceManager: NSObject {

//  Static Instance variable for Singleton
static var sharedSessionManager = ServiceManager()

//  Function to execute GET request and pass data from escaping closure
func executeGetRequest(with urlString: String, completion: @escaping (Data?) -> ()) {

    let url = URL.init(string: urlString)
    let urlRequest = URLRequest(url: url!)

    URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
        //  Log errors (if any)
        if error != nil {
            print(error.debugDescription)
        } else {
            //  Passing the data from closure to the calling method
            completion(data)
        }
    }.resume()  // Starting the dataTask
}

//  Function to perform a task - Calls executeGetRequest(with urlString:) and receives data from the closure.
func downloadMovies(from urlString: String, completion: @escaping ([Movie]) -> ()) {
    //  Calling executeGetRequest(with:)
    executeGetRequest(with: urlString) { (data) in  // Data received from closure
        do {
            //  JSON parsing
            let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
            if let results = responseDict!["results"] as? [[String:Any]] {
                var movies = [Movie]()
                for obj in results {
                    let movie = Movie(movieDict: obj)
                    movies.append(movie)
                }
                //  Passing parsed JSON data from closure to the calling method.
                completion(movies)
            }
        } catch {
            print("ERROR: could not retrieve response")
        }
    }
  }
}

下面是我如何使用单例类的示例。

ServiceManager.sharedSessionManager.downloadMovies(from: urlBase) { (movies : [Movie]) in   // Object received from closure
self.movies = movies
      DispatchQueue.main.async {
            //  Updating UI on main queue
            self.movieCollectionView.reloadData()
      }
}

我希望这可以帮助任何人寻找相同的解决方案。