在completionHandlers中存储值-Swift

在completionHandlers中存储值-Swift,swift,Swift,我正在创建一个completionHandler,它返回一个字典,但是当我在另一个类中调用这个方法时,它的值是nil func fetchLatestPosts(completionHandler: (responseDict: NSDictionary) -> Void in { // Bunch of JSON Parsing for dictionary to be completed var theDictionary = JSON Dictionary value respons

我正在创建一个
completionHandler
,它返回一个字典,但是当我在另一个类中调用这个方法时,它的值是nil

func fetchLatestPosts(completionHandler: (responseDict: NSDictionary) -> Void in {
// Bunch of JSON Parsing for dictionary to be completed
var theDictionary = JSON Dictionary value
responseDict = theDictionary as NSDictionary
}
然后我尝试在另一个类中调用它,以便可以查看
fetchLatestPost
字典中的值,并基于该值显示数据。 比如说,

func parseDictionary() {
NetworkManager.sharedInstance.fetchLatestPosts(responseDict: NSDictionary)
if (responseDict != nil) {
println("Dictionary is not empty")
}
这里的问题是,当我调用
fetchLatestPosts
函数时,我在尝试调用字典时收到一个
nil


简言之,我的问题是如何将值分配给存储在Xcode项目中并可以在其他地方调用的完成处理程序。您的示例代码无效,并且未显示正在使用的完成处理程序

我怀疑您误解了异步请求和完成处理程序的工作方式。下面是顺序

  • 调用函数并提供完成处理程序
  • 函数立即返回,并在将来某个时间运行请求
  • 完成后的下一行处理程序在请求开始处理之前运行。你的应用程序继续运行。没有可用的结果,因为请求尚未完成
  • 异步请求最终完成。原始方法调用完成处理程序。现在,结果在完成处理程序的代码中可用。完成处理程序代码执行处理结果所需的任何操作
  • 下面是一个带有完成处理程序的异步进程如何工作的实际示例:(您可以在Github上找到一个正在工作的Xcode项目,该项目演示了这段代码)

    首先是一个类AsyncManager,它模拟从internet下载图像:

    class AsyncManager
    {
      static let sharedAsyncManager = AsyncManager()
    
      func asyncFetchImage(#imageName: String, completion: (image: UIImage?, status: String) -> ())
      {
        println("Entering \(__FUNCTION__)")
    
        //Simulate a network operation by waiting 3 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__)")
      }
    }
    
    这是一个单身汉。它有一个静态let sharedAsyncManager,您可以使用它获取AsyncManager的单个实例

    AsyncManager提供一个方法asyncFetchImage,该方法采用图像名称和完成块。函数不会返回任何结果,因为它会在图像加载发生之前立即返回

    代码并没有真正从互联网下载图像。相反,它只是使用GCD call dispatch_after在加载映像和调用完成块之前等待3秒钟

    现在我创建了一个ViewController类,并给它一个“加载图像”按钮。我创建了一个
    IBOutlet
    图像视图
    到一个
    ui图像视图
    ,它将显示我要加载的图像

    我为Load Image按钮编写了一个iAction方法。以下是IBAction的外观:

    @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")
      }
    }
    
    现在,有趣的部分。以下是事件的顺序:

    我按下loadImage按钮。IBAction方法运行

    它获取对异步下载管理器单例的引用

    它显示一条消息,然后调用AsyncManager.asyncFetchImage。AsyncManager.asyncFetchImage方法在输入时显示一条消息,在3秒钟后排队调用以加载图像,显示一条“离开”消息,并在加载图像之前返回。没有要返回的内容,因为图像加载代码尚未运行

    视图控制器的loadImage方法显示“调用asyncFetchImage后”消息并返回

    几秒钟后,asyncFetchImage中的代码实际运行。它显示一条消息,加载图像,然后调用完成处理程序

    以下是运行上述代码时返回的消息集:

    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
    
    请注意,loadImage iAction的最后一行:

    println("After call to asyncFetchImage")
    

    在显示有关加载图像的消息之前显示消息。对asyncFetchImage的代码调用在任何工作完成之前立即返回。接下来将运行调用asyncFetchImage后的代码,但尚未加载映像。此时无法返回结果,因为图像加载尚未开始。

    您仍然不了解完成块是如何工作的。很可能是的,我是编程新手。抱歉。请参阅我的编辑。我添加了一个工作示例中的代码,显示了完成处理程序的实际工作方式。@Jack,我在Github上创建了一个名为的演示项目,演示了完成处理程序的工作方式。“我的编辑”中的代码取自该项目。我建议你下载并运行它。如果你不了解控制流是如何工作的,就添加断点。嘿,邓肯,我真的很感谢你发给我的演示项目,它帮助我理解了我想问的问题。我最初的问题是关于完成处理程序在异步调用期间存储值的部分,在您的示例中,该部分是将
    result
    status
    的值设置为
    image
    status
    完成(image:result,status:status)。我现在明白了,非常感谢你的帮助!