API JSON& UIPageViewController可选Nil [英] API JSON & UIPageViewController optional Nil

查看:134
本文介绍了API JSON& UIPageViewController可选Nil的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我正在尝试制作一个网页浏览滑块,使用此教程作为基础。

Okay, I am trying to work out a pageview slider that retrieves images url from an API using this tutorial as a base.

我已编码异步下载图像并将其附加到pageImages数组。该部分工作正常。

I have already coded the asynchronous downloading of images and appending it to the pageImages array. That part works fine.

但是,当我尝试在模拟器中运行应用程序时收到错误:

However, I received an error when I am trying to run the app in the simulator :


致命错误:在展开可选值时意外发现nil

fatal error: unexpectedly found nil while unwrapping an Optional value

出于某种原因,取出我调用助手方法viewControllerAtIndex后,JSON对象和填充pageImages数组发生。

For some reason, fetching the JSON objects and populating the pageImages Array happens after I call my helper method viewControllerAtIndex.

我的代码

class ViewController: UIViewController, UIPageViewControllerDataSource {

var pageViewController: UIPageViewController!
var pageImages = NSArray()
var jsonData = NSArray()

override func viewDidLoad() {
    super.viewDidLoad()

    ###THIS EXECUTES AFTER MY HELPER METHOD viewControllerAtIndex
    self.fetchPublishers()

    self.pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController

    self.pageViewController.dataSource = self

    var startVC = self.viewControllerAtIndex(0) as ContentViewController
    var viewControllers = NSArray(object: startVC)

    self.pageViewController.setViewControllers(viewControllers as [AnyObject], direction: .Forward, animated: true, completion: nil)

    self.pageViewController.view.frame = CGRectMake(0, 30, self.view.frame.width, self.view.frame.size.height)

    self.addChildViewController(self.pageViewController)
    self.view.addSubview(self.pageViewController.view)
    self.pageViewController.didMoveToParentViewController(self)
}

func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    var vc = viewController as! ContentViewController
    var index = vc.pageIndex as Int

    if (index == 0 || index == NSNotFound) {
        return nil
    }

    index--
    return self.viewControllerAtIndex(index)
}

func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {

    var vc = viewController as! ContentViewController
    var index = vc.pageIndex as Int

    if (index == NSNotFound) {
        return nil
    }

    index++

    if (index == self.pageImages.count) {
        return nil
    }

    return self.viewControllerAtIndex(index)

}

func viewControllerAtIndex(index: Int) -> ContentViewController
{
    if ((self.pageImages.count == 0) || (index >= self.pageImages.count)) {
        return ContentViewController()
    }

    var vc: ContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ContentViewController") as! ContentViewController

    vc.imageFile = self.pageImages[index] as! String
    vc.pageIndex = index

    return vc

}

func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
    return self.pageImages.count
}

func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
    return 0
}

func fetchPublishers () {

    var req:Request = Alamofire.request(OauthToken.Router.ReadPublishers(""))

    var aClosure =  {(req:NSURLRequest, response:NSHTTPURLResponse?, JSON:AnyObject?, error:NSError?) -> Void in

        if (error != nil) {
            println(error)
            println("Couldn't connection to server.")
        } else {

          dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {

            self.jsonData = JSON as! NSArray!

            var baseUrl: String = "http://0.0.0.0:3000"
            self.pageImages = JSON!.valueForKey("photo_url") as! NSArray!

            ###Prints/executes after
            println(self.pageImages)

          }

        }

    }

    req.responseJSON(aClosure)

}

} 

ContentViewController

class ContentViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!

var pageIndex: Int!
var imageFile: String!

override func viewDidLoad() {
    super.viewDidLoad()

    ####THE ERROR HAPPENS HERE
    self.imageView.image = UIImage(named: self.imageFile)
}

}

我该如何解决这个问题?

How can I fix this?

推荐答案

事情正在发生,因为引用 AlamoFire github页面:Alamofire中的网络是异步完成的。这意味着在从服务器收到响应之前不会执行 aClosure 中的代码,而是执行 viewDidLoad 无论如何都要继续。

Things are happening out of sequence because, to quote from the AlamoFire github page: "Networking in Alamofire is done asynchronously." That means that the code in aClosure is not executed until the response is received from the server, but execution of your viewDidLoad carries on regardless.

结果是,当通过调用 viewControllerAtIndex设置 startVC ,pageImages数组为空,并执行返回ContentViewController()。这实例化了一个空的内容视图控制器,由于它没有链接到故事板,因此插座 imageView 是nil(实际上 imageFile 是零)。这就是你得到错误的原因。

The consequence is that, when startVC is set by calling viewControllerAtIndex, the pageImages array is empty, and return ContentViewController() is executed. This instantiates an empty content view controller and, since it is not linked to the storyboard, the outlet imageView is nil (and indeed imageFile is nil). This is why you get the error.

所以你需要在 viewControllerAtIndex 中修改if语句以显示更多内容如果数组为空,则有用 - 可能是一个视图控制器,向用户发送数据正在下载的消息,以及系统正在运行的可视指示器。

So you need to amend that if statement in viewControllerAtIndex to display something more helpful if the array is empty - perhaps a view controller with a message to the user that the data is downloading, and a visual indicator that the system is working.

然后必须找到一种方法来在数据从服务器到达时重新加载页面视图控制器。为此,您应该在 aClosure 的末尾添加一些代码。在本教程中,有一个函数 restartAction ,它执行必要的操作,因此要么调用它,要么将代码复制到闭包中。

You then have to find a way to reload the page view controller when the data does arrive from the server. To do that, you should add some code at the end of your aClosure. In the tutorial, there is a function restartAction which does the necessary, so either call that, or copy the code into the closure.

最后,因为最后一步涉及UI更新,所以必须在主队列上运行。因此,您需要修改 dispatch_async 调用(在闭包中)以使用主队列,而不是全局队列。有关该问题的完整说明,请参见此答案

Finally, because that last step involves UI updates, it has to run on the main queue. So you need to amend your dispatch_async call (in the closure) to use the main queue, not the global queue. See this answer for a full explanation on that.

这篇关于API JSON& UIPageViewController可选Nil的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆