2016-04-24 70 views
6

我基本上必须使用在viewDidLoad中调用的方法。第一个获取用户的搜索首选项并将首选项保存到顶部的变量。之后,我想在第二个函数中访问和使用这些变量。但是现在当我想在第二个函数中访问它们时,变量总是为零。如何等待函数在iOS/Swift上结束,然后再启动第二个函数

如何调整我的viewDidLoad,所以第二个函数只执行一次,我的数据请求已成功执行?

var searchLocation = String() 
var searchLocationCoordinates = [String:Double]() 
var searchRange = Int() 


override func viewDidLoad() { 
    super.viewDidLoad() 

    // Gets the user's search preference 
    getTheSearchLocationAndRange() 

    // Loads the data from the database 
    loadDataFromDatabase() 
} 

到目前为止,我已阅读的东西与dispatch_asynch或完成处理程序。也许有人可以发布一些代码,我可以在我的viewDidLoad中使用,并使其工作?

+5

你不说的话,但getThSearchLocationAndRange必须是异步的?在这种情况下,您不应该等待,这会让您的GUI挂起。相反,您可以使第一个函数以完成块作为参数,并将第二个函数作为块体执行,另一种方法是执行块体。 – Gruntcakes

+0

好吧,是啊!你有一些示例代码给我看?但这也是我在完成处理程序中看到的其他帖子中的一个想法! – Mattk90

+0

getTheSearchLocationAndRange中是否有调度函数? – FredericP

回答

1

好吧,我已经找到了解决方案。我基本上在第一个结尾处调用函数。

所以基本上:

var searchLocation = String() 
    var searchLocationCoordinates = [String:Double]() 
    var searchRange = Int() 


    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Gets the user's search preference 
     getTheSearchLocationAndRange() 
    } 

    func getTheSearchLocationAndRange() { 
    // Code for getTheSearchLocationAndRange() 

    loadDataFromDatabase() 
    } 

    func loadDataFromDatabase(){ 
    // Code for loadDataFromDatabase() 
    } 
+1

这样做的问题是它使得'getTheSearchLocationAndRange()'函数不那么有用,除非它总是*应该调用'loadDataFromDatabase'。如果您希望该方法更加灵活,请使用完成块方法。 – milesper

+0

好的,我同意这一点。在我的情况下,我永远不会需要独立的两个功能。所以我想我可以像这样解决它。但我给你信用,你的解决方案可能是编程更好的解决方案! hahha – Mattk90

6

你可以使用Swift闭包!他们是为了这个。

请参考苹果指南:Closures

这里是你在特定情况下需要的代码。

FinishedDownload是关闭。当调用getTheSearchLocationAndRange()时,将执行其代码,直到等待该函数的所有进程完成的completed()行。一旦处理完成(例如下载),completed()调用关闭,激活getTheSearchLocationAndRange {() ->() in中定义的代码。因此,loadDataFromDatabase()仅在getTheSearchLocationAndRange()已完全执行并且数据存在(而不是无)时才被调用。

var searchLocation = String() 
    var searchLocationCoordinates = [String:Double]() 
    var searchRange = Int() 
    typealias FinishedDownload =() ->() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     getTheSearchLocationAndRange() 
    } 

    func getTheSearchLocationAndRange(completed: FinishedDownload) { 

      // Code for searching Location Range HERE 

      completed() 
    } 

    getTheSearchLocationAndRange {() ->() in 
     loadDataFromDatabase() 
    } 

我希望这个解决您的问题,并回答了你的问题:)

顺便说一句,关于“离开你的GUI挂”的一部分,Alamofire需要自动为您关心这一点。如果您不使用Alamofire,那么您将不得不手动将异步请求分配给后台线程,以便您的GUI不会无响应。

+0

如果我在getTheSearchLocationAndRange中有参数需要返回 – Sam

3

我写了一个演示项目,并将它发布到GitHub上,它模拟处理异步网络下载。看看DuncanMC/SwiftCompletionHandlers

请特别注意asyncFetchImage()方法,该方法几乎完全实现了该线程所讨论的内容:在内部使用异步方法,并在完成异步加载后采用它调用的完成块。

这是您应该使用的一般模式。编写一个采用完成块/关闭的方法。在内部,该方法调用它需要的任何异步函数,然后在异步方法调用的完成闭包内调用完成闭包。

功能asyncFetchImage看起来是这样的:

func asyncFetchImage(imageName imageName: String, 
    completion: (
    image: UIImage?, 
    status: String) ->()) 
{ 
    print("Entering \(#function)") 

    //Simulate a network operation by waiting a few seconds before loading an image 
    let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC))) 
    let queue = dispatch_get_main_queue() 
    dispatch_after(nSecDispatchTime, queue) 
    { 
    () -> Void in 
     let result = UIImage(named: imageName) 
     print("Loading image in background") 
     let status = result != nil ? "image loaded" : "Error loading image" 
     print("About to call completion handler") 
     completion(image: result, status: status) 
    } 
    print("Leaving \(#function)") 
}