如何从 Swift 中的闭包中获取 return 值?
How to return value from a Closure in Swift?
所以我在我的应用程序中使用 fabric plugin/Twitter-kit 来使用 twitter api。我想获取名人头像的图像 URL。下面是我的代码。
func getImageURL(celebrity :String) -> String{
var imageURL = ""
let client = TWTRAPIClient()
let statusesShowEndpoint = userSearch
let params = ["q": celebrity,
"page" : "1",
"count" : "1"
]
var clientError : NSError?
let request = client.URLRequestWithMethod("GET", URL: statusesShowEndpoint, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print("json: \(json)")
let profileImageURL: String? = json[0].valueForKey("profile_image_url_https") as? String
imageURL = self.cropTheUrlOfImage(profileImageURL!)
print(imageURL)
//how do i return the value back. confused ?????
return imageURL
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
return imageURL
}
我不知道如何 return 值,因为该方法在闭包完全执行之前完成。我是 swift 的新手,感谢任何帮助。
我想在 tableview 的 cellForRowIndexPath 中使用这个方法从 imageURl 下载图像。
你是对的,sendTwitterRequest
将在你的函数已经 returned 之后 return,所以外部函数无法 return 图像 URL。
相反,在闭包中,获取单元格中所需的 return 值并将其存储在某处(在成员变量中)并让 tableView 自行更新它(例如使用 tableView.reloadData()
).
这将导致它再次获取单元格 (cellForRow ...)。更改实现以使用存储调用值的成员变量。
您需要从 @escaping 闭包中 return。
改变功能
func getImageURL(celebrity: String) -> String {
}
到
func getImageURL(celebrity: String, completion: @escaping(String)->()) {
// your code
completion(imgURL)
}
您可以按照下面的方式使用它
getImageURL(celebrity: String) { (imgURL) in
self.imgURL = imgURL // Using self as the closure is running in background
}
这是一个示例,我如何编写多个带有闭包的方法来完成。
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()
}
}
我希望这对寻找相同解决方案的任何人有所帮助。
所以我在我的应用程序中使用 fabric plugin/Twitter-kit 来使用 twitter api。我想获取名人头像的图像 URL。下面是我的代码。
func getImageURL(celebrity :String) -> String{
var imageURL = ""
let client = TWTRAPIClient()
let statusesShowEndpoint = userSearch
let params = ["q": celebrity,
"page" : "1",
"count" : "1"
]
var clientError : NSError?
let request = client.URLRequestWithMethod("GET", URL: statusesShowEndpoint, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
print("json: \(json)")
let profileImageURL: String? = json[0].valueForKey("profile_image_url_https") as? String
imageURL = self.cropTheUrlOfImage(profileImageURL!)
print(imageURL)
//how do i return the value back. confused ?????
return imageURL
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
return imageURL
}
我不知道如何 return 值,因为该方法在闭包完全执行之前完成。我是 swift 的新手,感谢任何帮助。
我想在 tableview 的 cellForRowIndexPath 中使用这个方法从 imageURl 下载图像。
你是对的,sendTwitterRequest
将在你的函数已经 returned 之后 return,所以外部函数无法 return 图像 URL。
相反,在闭包中,获取单元格中所需的 return 值并将其存储在某处(在成员变量中)并让 tableView 自行更新它(例如使用 tableView.reloadData()
).
这将导致它再次获取单元格 (cellForRow ...)。更改实现以使用存储调用值的成员变量。
您需要从 @escaping 闭包中 return。 改变功能
func getImageURL(celebrity: String) -> String {
}
到
func getImageURL(celebrity: String, completion: @escaping(String)->()) {
// your code
completion(imgURL)
}
您可以按照下面的方式使用它
getImageURL(celebrity: String) { (imgURL) in
self.imgURL = imgURL // Using self as the closure is running in background
}
这是一个示例,我如何编写多个带有闭包的方法来完成。
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()
}
}
我希望这对寻找相同解决方案的任何人有所帮助。