如何从 Swift 中的闭包 return 3
How to return from closures in Swift 3
我曾经在 Objective-C 中创建一个单例 class 来执行我代码中的所有服务调用。但是,swift 使用闭包,我无法在 Swift 中获得相同的结果。有什么方法可以在 Swift 3 中做同样的事情吗?
@implementation ServiceManager
+(id)sharedManager {
static ServiceManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(NSURLSession *)urlSession {
if (_urlSession) {
return _urlSession;
}
NSURLSessionConfiguration *defaultConfigObject =
[NSURLSessionConfiguration defaultSessionConfiguration];
_urlSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
_urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
_urlSession.sessionDescription = @"net.socialInvesting.nsurlsession";
return _urlSession;
}
-(void)ExecuteRequest:(NSURLRequest *)request withCompletion:(void (^)(id result, NSError *error))completionBlock {
NSURLSessionDataTask * dataTask =[[self urlSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil) {
id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
completionBlock(result,error);
} else {
NSLog(@"Error: %@", error.localizedDescription);
completionBlock(nil, error);
}
}];
[dataTask resume];
}
@end
我在下面的代码片段中调用这个函数。
[sharedServiceManager ExecuteRequest:urlRequest withCompletion:^(id result, NSError *error) {
if (result) {
LoginModel *model = [[LoginModel alloc]initWithDictionary:result error:NULL];
ResponseManager *manager = [ResponseManager sharedManager];
manager.loginResponse = model;
completionBlock(YES,NULL);
} else {
completionBlock(NO,error);
}
}];
这就是我在 swift 中尝试执行类似执行的方式。但无法 return 值。
import UIKit
class ServiceManager: UIView {
var session = URLSession.shared
static let sharedSessionManager = ServiceManager()
class func sharedManager() -> ServiceManager {
return sharedSessionManager
}
func executeGetRequest(with urlString: String, inputDictionary:[String : Any], completionHandler: @escaping () -> (Error?, [[String : Any]])) {
let url = URL.init(string: urlString)
let urlRequest = URLRequest(url: url!)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print("ERROR: could not execute request")
} else {
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler // How to return results and Error from here to the calling function
}
} catch {
print("ERROR: could not retrieve response")
}
}
}
task.resume()
}
}
如有任何帮助,我们将不胜感激。
您只需编写 completionHandler(arg1, arg2,...)
并将您想要 return 的值放在括号内,就像调用函数时那样。您应该将完成处理程序更改为其两个参数的 return 可选值,因为如果您收到错误,最好 return 一个 nil 而不是一个空字典。
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler(nil, responseDict)
}
} catch {
completionHandler(error, nil)
}
感谢您的帮助。
通过对闭包的更多研究,我得到了结果。
下面是我创建的Singleton ServiceManager。
class ServiceManager: NSObject {
// Static Instance variable for Singleton
static var sharedSessionManager = ServiceManager()
// Preventing initialisation from any other source.
private init() {
}
// 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()
}
}
我希望这可以帮助任何正在寻找类似解决方案的人。
我曾经在 Objective-C 中创建一个单例 class 来执行我代码中的所有服务调用。但是,swift 使用闭包,我无法在 Swift 中获得相同的结果。有什么方法可以在 Swift 3 中做同样的事情吗?
@implementation ServiceManager
+(id)sharedManager {
static ServiceManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
-(NSURLSession *)urlSession {
if (_urlSession) {
return _urlSession;
}
NSURLSessionConfiguration *defaultConfigObject =
[NSURLSessionConfiguration defaultSessionConfiguration];
_urlSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
_urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
_urlSession.sessionDescription = @"net.socialInvesting.nsurlsession";
return _urlSession;
}
-(void)ExecuteRequest:(NSURLRequest *)request withCompletion:(void (^)(id result, NSError *error))completionBlock {
NSURLSessionDataTask * dataTask =[[self urlSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error == nil) {
id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
completionBlock(result,error);
} else {
NSLog(@"Error: %@", error.localizedDescription);
completionBlock(nil, error);
}
}];
[dataTask resume];
}
@end
我在下面的代码片段中调用这个函数。
[sharedServiceManager ExecuteRequest:urlRequest withCompletion:^(id result, NSError *error) {
if (result) {
LoginModel *model = [[LoginModel alloc]initWithDictionary:result error:NULL];
ResponseManager *manager = [ResponseManager sharedManager];
manager.loginResponse = model;
completionBlock(YES,NULL);
} else {
completionBlock(NO,error);
}
}];
这就是我在 swift 中尝试执行类似执行的方式。但无法 return 值。
import UIKit
class ServiceManager: UIView {
var session = URLSession.shared
static let sharedSessionManager = ServiceManager()
class func sharedManager() -> ServiceManager {
return sharedSessionManager
}
func executeGetRequest(with urlString: String, inputDictionary:[String : Any], completionHandler: @escaping () -> (Error?, [[String : Any]])) {
let url = URL.init(string: urlString)
let urlRequest = URLRequest(url: url!)
let task = session.dataTask(with: urlRequest) { (data, response, error) in
if error != nil {
print("ERROR: could not execute request")
} else {
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler // How to return results and Error from here to the calling function
}
} catch {
print("ERROR: could not retrieve response")
}
}
}
task.resume()
}
}
如有任何帮助,我们将不胜感激。
您只需编写 completionHandler(arg1, arg2,...)
并将您想要 return 的值放在括号内,就像调用函数时那样。您应该将完成处理程序更改为其两个参数的 return 可选值,因为如果您收到错误,最好 return 一个 nil 而不是一个空字典。
do {
let responseDict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
if let results = responseDict!["results"] as? [[String:Any]] {
completionHandler(nil, responseDict)
}
} catch {
completionHandler(error, nil)
}
感谢您的帮助。
通过对闭包的更多研究,我得到了结果。
下面是我创建的Singleton ServiceManager。
class ServiceManager: NSObject {
// Static Instance variable for Singleton
static var sharedSessionManager = ServiceManager()
// Preventing initialisation from any other source.
private init() {
}
// 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()
}
}
我希望这可以帮助任何正在寻找类似解决方案的人。