2016-03-12 36 views
0

让我通过说我是Swift 2的新手,并构建我的第一个调用api(php)数据(JSON)的应用程序。我遇到的问题是,当我调用api时,其他函数在api可以发回数据之前运行。Swift 2 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 
    } 
} 

回答

1

因此,我假设你的Render()方法在数据从api回来之前被调用?在视图控制器中保存你的API调用代码是不好的设计,但是因为你是新的,我不会在这方面进行扩展。在你的情况下,就像在viewDidLoad()中调用Render()方法一样简单 - 在完成从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的方法是可重复使用和浏览器只是处理时,得到的数据会发生什么。如果你在等待屏幕中间放一个UIActivityIndi​​cator会很好,那么它会看起来很整齐,专业:P

+0

我正在构建一个包含十个问题的测验样式应用程序。在每个被回答的问题之后,调用Render()方法来填充下一个问题和选项。我有兴趣了解API调用应该去哪里,我正在学习,这听起来像我需要更多地了解它。感谢您的反馈 – Mike

+0

因此,基本上,当视图加载时,您从测验的API中获取一些数据?我将编辑答案 – FruitAddict

+0

正确,我抓住一个带有十个元素的JSON对象,并将其推入列表数组中。 – Mike

相关问题