eureka19
eureka19

Reputation: 3060

Loading the server response into the UICollectionView

I have a UIViewController class where I'm trying to populate the data into my UICollectionView

//  HomeController.swift


import UIKit
import SwiftyJSON

class HomeController: UICollectionViewController, 
UICollectionViewDelegateFlowLayout, TaskServiceManagerDelegate {
func didUpdate(sender: TaskServiceManager) {
    self.collectionView?.reloadData()
  }

    var taskList:JSON? = nil

    override func viewDidLoad() {
    super.viewDidLoad()

    // getting the task list to populate the UICollectionView
    let taskServiceManager:TaskServiceManager = TaskServiceManager()
    taskList = taskServiceManager.getAllTasks()
    collectionView?.dataSource = self;
    collectionView?.delegate = self;
    navigationItem.title = "Test"
    collectionView?.backgroundColor = UIColor.lightGray
    collectionView?.register(QuestionCell.self, forCellWithReuseIdentifier: "cellId")
    }

    override func viewDidAppear(_ animated: Bool) {

    }

    override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // getting the task list to populate the UICollectionView
    let taskServiceManager:TaskServiceManager = TaskServiceManager()
    taskList = taskServiceManager.getAllTasks()
    collectionView?.dataSource = self;
    collectionView?.delegate = self;
    }

    override func collectionView(_ collectionView: UICollectionView,
                             numberOfItemsInSection section: Int) -> Int {
    return (taskList?.count)!
  }
}

I have another class TaskServiceManager where I'm making a REST api call and getting the data.

//  TaskServiceManager.swift

import UIKit
import Alamofire
import SwiftyJSON

class TaskServiceManager : NSObject{

var delegate: TaskServiceManagerDelegate?


func getAllTasks() -> JSON {
    var swiftyJsonVar: JSON = []
    Alamofire.request(url, headers: getHeaders()).responseJSON { (responseData) -> Void in
        print("Status Code: \(responseData.response?.statusCode)")
        if((responseData.result.value) != nil) {
            swiftyJsonVar = JSON(responseData.result.value!)
            print(swiftyJsonVar)
            print("Task List Count: \(swiftyJsonVar.array?.count)")
        }
    }
    return swiftyJsonVar
}

}

protocol TaskServiceManagerDelegate {
  func didUpdate(sender: TaskServiceManager)
}

The taskList?.count in the numberOfItemsInSection returns 0 even though I get a success from the api response with count as 6. Why is it so?

How do I refer the HomeController from the TaskServiceManager class?

Also, why does my TaskServiceManagerDelegate doesn't reflect the UICollectionView?

Upvotes: 1

Views: 859

Answers (2)

Sharad Chauhan
Sharad Chauhan

Reputation: 4891

No need of delegate to fetch data from API, completion handlers are better choice for this kind of task.

Make this change in your function :

func getAllTasks(completion:@escaping(JSON)->()) {
    var swiftyJsonVar: JSON = []
    Alamofire.request(url, headers: getHeaders()).responseJSON { (responseData) -> Void in
        print("Status Code: \(responseData.response?.statusCode)")
        if((responseData.result.value) != nil) {
            swiftyJsonVar = JSON(responseData.result.value!)
            print(swiftyJsonVar)
            print("Task List Count: \(swiftyJsonVar.array?.count)")
            completion(swiftyJsonVar)
        }
    }
}

To call it from your another class:

TaskServiceManager().getAllTasks { (tasks) in
   print("tasks : \(tasks)")
   //here reload your collection view
}

You are doing everything right except return statement. API calls are asynchronous and so your return statement is getting called before your network request is over. You need a completion callback to return the data when you get response.

And your delegation is incomplete. If you want to the delegation method then you need add these lines.

In viewDidLoad() after :

let taskServiceManager:TaskServiceManager = TaskServiceManager()

you need to assign your HomeController's instance to delegate variable of TaskServiceManager class

taskServiceManager.delegate = self

And in TaskServiceManager class when you get data from server you need to pass it using your delegate method, I don't know why you are trying to pass instance of TaskServiceManager in delegate method ?

protocol TaskServiceManagerDelegate {
  func didUpdate(sender: TaskServiceManager) // Why ?
  // func didUpdate(serverData: JSON) // Maybe this is what you need
}

To call delegate method one last step without any return statement :

func getAllTasks() {
    var swiftyJsonVar: JSON = []
    Alamofire.request(url, headers: getHeaders()).responseJSON { (responseData) -> Void in
        print("Status Code: \(responseData.response?.statusCode)")
        if((responseData.result.value) != nil) {
            swiftyJsonVar = JSON(responseData.result.value!)
            print(swiftyJsonVar)
            print("Task List Count: \(swiftyJsonVar.array?.count)")
            delegate.didUpdate(serverData: swiftyJsonVar) // this is to pass data 
        }
    }
}

Now this function in your HomeController will be called (I changed the data to serverData instead of TaskServiceManager) :

func didUpdate(serverData: dataFormServer) {
    print("dataFormServer : \(dataFormServer)")
    self.collectionView?.reloadData()
}

Upvotes: 4

sanjaykmwt
sanjaykmwt

Reputation: 605

you forgot to call the didUpdate function after successful API call. You need to reload the collectionView after the successful API call. The reason is API calls are asynchronous in nature

Upvotes: 0

Related Questions