API JSON и UIPageViewController необязательно Nil

Хорошо, я пытаюсь разработать ползунок просмотра страниц, который извлекает URL-адрес изображений из API, используя этот tutorial в качестве основы.

Я уже закодировал асинхронную загрузку изображений и добавление их в массив pageImages. Эта часть работает нормально.

Однако я получил сообщение об ошибке, когда пытаюсь запустить приложение в симуляторе:

фатальная ошибка: неожиданно найдено nil при развертывании необязательного значения

По какой-то причине выборка объектов JSON и заполнение массива pageImages происходит после того, как я вызываю вспомогательный метод 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)

}

} 

Контентвиевконтроллер

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)
}

}

Как я могу это исправить?


person Serge Pedroza    schedule 18.04.2015    source источник


Ответы (1)


Все происходит не по порядку, потому что, цитируя страницу github AlamoFire: "Сеть в Alamofire выполнена асинхронно». Это означает, что код в aClosure не выполняется до тех пор, пока не будет получен ответ от сервера, но выполнение вашего viewDidLoad продолжается независимо от этого.

Следствием этого является то, что когда startVC устанавливается путем вызова viewControllerAtIndex, массив pageImages пуст, и выполняется return ContentViewController(). Это создает пустой контроллер представления контента, и, поскольку он не связан с раскадровкой, выход imageView равен нулю (и действительно imageFile равен нулю). Вот почему вы получаете ошибку.

Таким образом, вам нужно изменить это выражение if в viewControllerAtIndex, чтобы отображать что-то более полезное, если массив пуст — возможно, контроллер представления с сообщением пользователю о загрузке данных и визуальным индикатором того, что система работает.

Затем вам нужно найти способ перезагрузить контроллер просмотра страницы, когда данные поступят с сервера. Для этого вам нужно добавить некоторый код в конец файла aClosure. В туториале есть функция restartAction, которая делает все необходимое, так что либо вызовите ее, либо скопируйте код в замыкание.

Наконец, поскольку этот последний шаг включает обновления пользовательского интерфейса, он должен выполняться в основной очереди. Поэтому вам нужно изменить свой вызов dispatch_async (в закрытии), чтобы использовать основную очередь, а не глобальную очередь. См. этот ответ для полного объяснения этого.

person pbasdf    schedule 18.04.2015