为什么Microsoft Azure(或一般的Swift)无法更新变量以在表查询后返回?

Evo*_*Sae 5 sql iphone azure ios swift

我一直在关注成功查询表的Microsoft Azure 文档(插入,读取和更新项目到数据库工作正常),但在一个简单的方法结束时,直接关闭文档:

func getAllEventIDs() -> [String] {
    var events:[String] = [] //this is to be updated
    let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let client = delegate.client! //boiler-plate for azure

    let itemTable = client.tableWithName("Events")
    itemTable.query().readWithCompletion { 
    //something about this query block might be preventing successful initialization to the events array
        (result:MSQueryResult!, error) in
        //usually error-checking here
        for item in result.items {
            events.append(item.valueForKey("id") as! String)
            //returning events here...
        }
        //...and here (almost) work, since Swift expects a return of type Void
    }
    return events //still empty
}
Run Code Online (Sandbox Code Playgroud)

可能不会将数组作为参数传递,因为该.append函数将改变该数组.

返回的值只是初始的空数组.但是,这个问题似乎很大程度上源于Azure的查询代码块,而不是来自Swift本身.

一个更简单的例子:

func returnValueArray() -> [Int] {
    var array:[Int] = [0,0,0,0]
    var num:Int = 3
    for var n = 0; n < array.count; n++ {
        array[n] = num
    }
    return array
}
Run Code Online (Sandbox Code Playgroud)

返回[3,3,3,3].同样,不是Swift的问题,但Swift可能已经体现了Azure的回归问题.

如何在查询方法结束时返回所需的更新数组?是否可以将可变数组传入方法,追加值,然后返回该数组?

Dun*_*n C 7

您问:"如何在查询方法结束时返回所需的更新数组?" 简答:你做不到.

这是异步编码的基础.

readWithCompletion方法是异步的.它将您在后台处理的请求排队,并立即返回.

您的return events //still empty代码在读取请求开始处理之前执行.

您需要重构您的getAllEventIDs方法以将完成块作为参数.该完成块将传递给您的事件数组.然后在完成块内部为readWithCompletion您调用方法的完成块getAllEventIDs.

所以当你调用时getAllEventIDs,你会传递一个完成块来完成你需要对events数组做的事情.

编辑:

我创建了一个名为SwiftCompletionHandlers的Github项目,该项目说明了这一点以及如何处理它.它有一个AsyncManager模拟异步下载的示例类.

https://github.com/DuncanMC/SwiftCompletionHandlers

它有一个如下所示的方法:

func asyncFetchImage(#imageName: String,
  completion: (
    image: UIImage?,
    status: String) -> ())
  {
    println("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)
        println("Loading image in background")
        let status = result != nil ? "image loaded" : "Error loading image"
        println("About to call completion handler")
        completion(image: result, status: status)
    }
    println("Leaving \(__FUNCTION__)")
  }
Run Code Online (Sandbox Code Playgroud)

它需要一个文件名和一个完成块.完成块传递UIImage可选和String状态消息.

下载完成后,该方法将调用完成块(也称为闭包).

以下是调用此方法的代码:

  @IBAction func loadImage(sender: UIButton)
  {
    let theAsyncManager = AsyncManager.sharedAsyncManager
    println("about to call asyncFetchImage")
    theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115")
      {
        (image, status) -> () in
        println("Beginning completion block")
        self.theImageView.image = image
        println("In completion block, status = \(status)")
    }
    println("After call to asyncFetchImage")
  }
Run Code Online (Sandbox Code Playgroud)

println语句的输出是理解正在发生的事情的关键:

about to call asyncFetchImage
Entering asyncFetchImage(imageName:completion:)
Leaving asyncFetchImage(imageName:completion:)
After call to asyncFetchImage
Loading image in background
About to call completion handler
Beginning completion block
In completion block, status = image loaded
Run Code Online (Sandbox Code Playgroud)

请注意,在"在后台加载图像"消息之前打印"Leaving asyncFetchImage"和"After call to asyncFetchImage"消息.然后是"关于调用完成处理程序",然后是"开始完成块".

因此,实际的异步工作甚至在loadImage函数返回之后才开始.

如果您不理解我所描述的内容,请下载项目并进行试用,然后设置断点并观察它的执行情况.