Swift URLSession not working before making PageView

I have read this post, but I couldn't solve my problem.
DispatchQueue.main.async code cannot work to my code.
I think my problem is a little bit different from that. So I post my question.

I have 3 views.

enter image description here

FirstView is a table view that user can select their choice.
SecondView is a view that handles UIPageViewControllerDelegate and DataSource.
ThirdView is a view which will be page views of Second view.
(The view at the bottom is PageViewController)

When user selects and tap the button on the First View, it goes to the Second view.
Then, Second View presents the result. (Actually, Third View shows the result, but it seems to be just shown in the Second View.)

The contents of the result are from the DB on server based on user's selection in the FirstView.

I thought that I need to fetched the result from server in the SecondView before presenting results on the ThirdView.

So I write the fetching code on the viewDidLoad in the SecondView's View Controller.

Here's the data model code

struct MyData: Decodable {
let a: String
let b: String
let c: String
}

Here's the Second View class code

class SecondView: UIViewController, UIPageViewControllerDelegate, 
UIPageViewControllerDataSource {

var pageViewController: UIPageViewController!
let pageControl: UIPageControl = UIPageControl()
let pageControlHeight: CGFloat = 20

var passedFromFirstVC: [String] = []
var pageTitle: [String] = []

override func viewDidLoad() {
    super.viewDidLoad()

    var request = URLRequest(url: NSURL(string: "http://xxxxx.xxx/" )! as URL)
    request.httpMethod = "POST"
    var postString = "xxxxxx"
    request.httpBody = postString.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request) {
        (data, response, error) in

        if error != nil {
            return
        }

        guard let data = data else { return }

        do {
            let fetchedData = try JSONDecoder().decode([MyData].self, from: data)
            print(fetchedData)
            self.pageTitle.append(fetchedData[x].xx)

         } catch let jsonErr {
                print("Error serializing json:", jsonErr)
         }
    }
    task.resume()

And in viewDidLoad code, the pageViewController codes are there.
Here's the residual codes in viewDidLoad.

    self.pageViewController = self.storyboard?.instantiateViewController(withIdentifier: "pageviewcontroller") as! UIPageViewController
    self.pageViewController.delegate = self
    self.pageViewController.dataSource = self
    self.pageViewController.view.frame = CGRect(x: 0, y: 65, width: view.frame.width, height: view.frame.height)
    let startVC = self.viewControllerAtIndex(index: 0) as! ContentViewController
    let viewControllers = NSArray(object: startVC)
    self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: true, completion: nil)
    self.addChildViewController(self.pageViewController)
    self.view.addSubview(self.pageViewController.view)
    self.pageViewController.didMove(toParentViewController: self)
}

And to make page index, this code is followed. Here's the code.

func viewControllerAtIndex(index: Int) -> ContentViewController {

    let vc: ContentViewController = self.storyboard?.instantiateViewController(withIdentifier: "ContentViewController") as! ContentViewController

    vc.pageIndex = index
    print("page just has been moved...")
    print(pageTitles)

    vc.titleText = pageTitles[index]
    return vc
}

But, when I run the app, it stops vc.titleText = pageTitles[index] in this code.
Because, pageTitles are nil.

So I set a breakpoint on the viewDidLoad, and I found that task had not been compiled.

It ignores task and task.resume() code, and then complies the following codes.

So, DispatchQueue.main.async code cannot work to my code.

But, when I set certain initial value in pageTitle(even after task.resume()), then task had been compiled after compiling codes related to other PageViewController.

And, when I made this code in another project with a just single ViewController(not like my PageViewController), it also compiles task code in viewDidLoad.

Why task code in this question had not been compiled?

And, how can I fetch data before compiling page view controller code?

1 answer

  • answered 2018-11-08 07:57 Hoo

    I found the answer from comments from this post.
    This is the comment.

    Move the line print(scenarioArray) and everything you want to do afterwards from viewDidLoad into the completion block after self.scenarioArray = ....

    The point is 'put other codes in viewDidLoad into completion block(in this code, do block) by making DispatchQueue.main.async { code } in do block.

    Here's the answer.

    override func viewDidLoad() {
    
        super.viewDidLoad()
        var request = URLRequest(url: NSURL(string: "http://xxxxx.xxx/" )! as URL)
        request.httpMethod = "POST"
        var postString = "xxxxxx"
        request.httpBody = postString.data(using: String.Encoding.utf8)
    
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
                if error != nil {
                return
                }
                guard let data = data else { return }
    
                do {
                    let fetchedData = try JSONDecoder().decode([MyData].self, from: data)
                    self.pageTitle.append(fetchedData[x].xx)
    
                    DispatchQueue.main.async {
                        self.pageViewController = self.storyboard?.instantiateViewController(withIdentifier: "pageviewcontroller") as! UIPageViewController
                        self.pageViewController.delegate = self
                        self.pageViewController.dataSource = self
                        self.pageViewController.view.frame = CGRect(x: 0, y: 65, width: view.frame.width, height: view.frame.height)
                        let startVC = self.viewControllerAtIndex(index: 0) as! ContentViewController
                        let viewControllers = NSArray(object: startVC)
                        self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: true, completion: nil)
                        self.addChildViewController(self.pageViewController)
                        self.view.addSubview(self.pageViewController.view)
                        self.pageViewController.didMove(toParentViewController: self)
                     }
                } catch let jsonErr {
                        print("Error serializing json:", jsonErr)
                }
            }
        task.resume()
    }
    


    But, be aware of view in CGRect width and height code.

    self.pageViewController.view.frame = CGRect(x: 0, y: 65, width: view.frame.width, height: view.frame.height)
    

    When you put this code in 'do' block, view will bring ambiguous error of.

    Then modify that code to this.

    self.pageViewController.view.frame = CGRect(x: 0, y: 65, width: self.pageViewController.view.frame.width, height: self.pageViewController.view.frame.height)
    

    Hope this help!