让我先说明我对Swift 2非常新,并且正在构建我的第一个应用程序,它调用api(php)来获取数据(JSON)。我遇到的问题是当我调用api时,其他函数在api发送回数据之前运行。
我已经研究了某种类型的onComplete来在api响应完成后调用函数。我相信大多数人这很容易,但我似乎无法将其视为我们的。
提前致谢!
class ViewController: UIViewController {
var Selects = [Selectors]()
var list = [AnyObject]()
var options = [String]()
var index = 0
@IBOutlet var Buttons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
self.API()
self.Render()
}
func API() {
let url = NSURL(string: "http:api.php")
let request = NSMutableURLRequest(URL: url!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if data == nil {
print("request failed \(error)")
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let songs = json["songs"] as? [[String: AnyObject]] {
for song in songs {
self.list.append(song)
}
}
self.Selects = [Selectors(Name: self.list[self.index]["name"] as? String, Options: self.BuildOptions(), Correct: 2)]
}
catch let error as NSError {
print("json error: \(error.localizedDescription)")
}
}
task.resume()
}
func BuildOptions() {
// BuildOptions stuff happens here
}
func Render() {
// I do stuff here with the data
}
}
答案 0 :(得分:1)
所以我假设在从api返回数据之前调用了Render()
方法?在视图控制器中保存api-calling代码是糟糕的设计,但是随着你的不断发展,我不会对此进行扩展。在您的情况下,就像在Render()
中不调用viewDidLoad()
方法一样简单 - 在您完成解析JSON中的数据之后调用它(在self.Selects = [Selectors...
之后线)。异步调用NSURLSession.sharedSession().dataTaskWithRequest(request)
方法,并且在获取数据完成此方法后执行带有data, response, error
参数的回调块,因此可能会在viewDidLoad
完成并且最终完成后执行没有数据要处理,因为异步方法仍在等待来自API的响应。
编辑 - 谈到处理api调用,将它们与特定视图控制器分开以保持干净的可重用代码库是明智之举。你应该调用API并等待它的回调,所以我只是对你的API函数这样做,它看起来像这样:
static func callAPI(callback: [AnyObject]? -> Void ) {
let url = NSURL(string: "http:api.php")
let request = NSMutableURLRequest(URL: url!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if data == nil {
completion(nil)
}
do {
var list = [AnyObject]()
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let songs = json["songs"] as? [[String: AnyObject]] {
for song in songs {
self.list.append(song)
}
}
completion(list)
}
catch let error as NSError {
print("json error: \(error.localizedDescription)")
completion(nil)
}
}
task.resume()
}
一般来说,方法应该做一个特定的事情 - 在你的情况下调用api并返回数据或错误。在回调时在视图控制器中初始化选择器。您的视图控制器viewDidLoad
使用上面的代码看起来像这样:
override func viewDidLoad() {
super.viewDidLoad()
YourApiCallingClass.callApi() {
result in
if let list = result {
self.list = list
self.Selects = [Selectors(Name: self.list[self.index]["name"] as? String, Options: self.BuildOptions(), Correct: 2)]
self.Render()
} else {
//Handle situation where no data will be returned, you can add second parameter to the closue in callApi method that will hold your custom errors just as the dataTaskWithRequest does :D
}
}
}
现在您可以很好地分离关注点,API方法可重用,视图控制器只处理获取数据时发生的事情。如果你在等待的同时在屏幕中间拍了一个UIActivityIndicator,它会很好看,它看起来很整洁和专业:P