Swift How to refactor getting data from API? - ios

I'm trying to get data from API and display it in the tableView.
Because getting data from API used multiple times in my application. So I want to make it reusable.
I create a class called GetProducts to get the data from API, and save it to Posts
class GetProducts{
static var products = [Product]()
static func loadProducts( _ filter: [String:String]) {
// get data from API
// append products to products list
}
}
In the viewController, I want to fetch the products data from GetProducts class, and display it in the tableView
class MainViewController: UIViewController,UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
GetPeoducts.loadProducts([...])
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return GetProducts.products.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(for: indexPath) as ProductTableViewCell
cell.products = GetProducts.products
return cell
}
}
However, in the tableView, the products list is empty.
I cannot figure it out which step was wrong. Is there anyone can help me with logic?
Thanks in advance!

Basically, what I'm doing is using completion handler
class GetPosts{
static var products = [Product]()
static func loadProducts( _ filter: [String:String], completion:(([Product]) -> Void)?) {
// get data from API
// append products to products list
completion?(self.products)
}
}
Call the loadPoducts in ViewController:
class MainViewController: UIViewController,UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var tableView: UITableView!
var products = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
GetPeoducts.loadProducts(/*some params*/){ (products) in
self.products = products
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.products.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(for: indexPath) as ProductTableViewCell
cell.products = self.products
return cell
}
}
Thank you! #rmaddy #Vanya #Aakash #Jelord Rey

Related

Slide Out Bar with sub categories in swift

There are some rows in table view. Each row opens a new view. Now I want to show some sub categories on click of Particular row. each of this sub category opens different view. I am using only 1 section. Any ideas?
Simply do this.
class CategoriesListViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var filterCategories = [CategoryViewModel]()
override func viewDidLoad() {
super.viewDidLoad()
tfSearch.placeholder = LocalizeKey.search.localized
getCategories()
// Do any additional setup after loading the view.
}
extension CategoriesListViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filterCategories.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CategoryCellTableView
let category = filterCategories[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let controller : SubCategoriesListViewController = ViewControllerManager.shared.find() {
controller.selectedCategory = self.filterCategories[indexPath.row]
self.pushViewController(controller : controller)
}
}
Sub-Categories will be subclassed from the main categories and override the table view selection methods and do whatever you want to do.
class SubCategoriesListViewController: CategoriesListViewController {
#IBOutlet weak var tableView: UITableView!
var filterCategories = [CategoryViewModel]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let controller = DifferentViewController()
self.pushViewController(controller : controller)
}

How to select specific Cell in UITableView and save it in String var - Swift

I want to take selected cell as a text, and save it in "var productName" as a String. I've tried to use didSelectRowAt funcion, but I don't know how to implement it.
That's my code:
import UIKit
class ChooseProductViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var productName: String? = ""
var workModel: ActualValues?
var closureBlock2: (() -> Void)?
#IBOutlet weak var checkButton: UIButton!
let productList : [String] = ["Almond 20g",
"Almond 40g",
"Baharat Spice Mix 2g",
"Baharat Spice Mix 4g",
]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
myCell.textLabel?.text = productList[indexPath.row]
return myCell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func checkButton(_ sender: UIButton) {
workModel?.product = productName
closureBlock2?()
self.dismiss(animated: true, completion: nil)
}
func configureProduct(model: ActualValues) {
workModel = model
}
}
How can I fix it?
Something like this is probably what you want?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
productName = productList[indexPath.row]
}
And make sure you've set the data source and delegate, and that the table view allows seletion:
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsSelection = true
tableView.dataSource = self
tableView.delegate = self
}

How to load data into table view

How do I load data into my UITableView? Can anyone please kindly help me with this issue:
why not load to cellForRowAt
pPlandDetailId ==>Optional(1)
Driver ==> Driver Name:Boonma,Pongpat
carRegistrtation ==> Car Registrtation:60-7620
StoreLocation ==> ["S.Surathani"]
pDepartureDateTime ==> ["18/01/2019 20:00"]
import UIKit
class StoreListMainViewController: UIViewController,UITableViewDelegate, UITableViewDataSource{
// TableView
#IBOutlet weak var tableView: UITableView!
var StoreLocation: [String] = []
var getDepartureTime: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
createTableiew()
}//Main Method
// TableView
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return StoreLocation.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? cellTableViewCell
cell!.Location.text = StoreLocation[indexPath.row]
cell!.DepartureTime.text = getDepartureTime[indexPath.row]
print("cell!.Location.text ==>\(String(describing: cell!.Location.text) )")
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "gotoTempMonitorStoreList") as? StoreListTempMonitorViewController
self.navigationController?.pushViewController(vc!, animated: true)
}
// Create UI Table view
func createTableiew() -> Void {
tableView.delegate = self
tableView.dataSource = self
}//createTableiew
import UIKit
class cellTableViewCell: UITableViewCell {
#IBOutlet weak var Location: UILabel!
#IBOutlet weak var DepartureTime: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
reload tableview tableView.reload() where you have received data.
I suggest you to first fetch the data and later try to reload your table view.
Once you set the array to table values automatically they will get displayed in table provided you code object's properties to cell's Outlet values.
Since you are not using a UITableViewController you need to set a delegate and a dataSource to your tableView object.
Looks something like this:
override func viewDidLoad() {
tableView.dataSource = self
tableView.delegate = self
}
That's it. Enjoy

swift: tableview does not work after reloadData

i have a tableview in a viewcontroller and because i need to reuse most of the code for another table i created an extra class:
class StatisticsViewDelegate: NSObject, UITableViewDelegate, UITableViewDataSource {
var defaultList:[String]
var infolist:[String] = []
var tableView:UITableView
var controller:UIViewController?
init(defaultList:[String], view:UITableView, controller:UIViewController?) {
self.defaultList = defaultList
self.controller = controller
tableView = view
super.init()
tableView.delegate = self
tableView.dataSource = self
loadTable()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return infolist.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "infocell", for: indexPath) as! TableViewCell
// [fill cell]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// [...]
}
func loadTable() {
DispatchQueue.global(qos: .userInitiated).async {
//[...]
// in this case:
self.infolist = self.defaultList
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
and in my UITViewController in the viewDidLoad():
delegate = StatisticsViewDelegate(defaultList: defaultList, view: tableView, controller:self)
delegate is a member of the ViewController
now when i run it, the function func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) never gets called. The func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) gets called however(before and after the reload) and returns the correct number(in my case 4). The TableView isn't visible at all. Where is my error?
Maybe you can use the subclassing strategy to resolve your problem. There are many reference passed to your class and if you forgot to clean that up you will be have memory leaks in your hand. So I'll suggest the simple example as below. You can modify as you like and let me know if that was what you are after. If not please pardon me.
//This will be parent class that will handle all table methods, so you need to write only once the delegates and stuffs
class MyCommonTableController: UITableViewController {
var infoList = [String]()
// MARK: - TableView Delegate and Datsource Impl
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return infoList.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 55.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = infoList[indexPath.row]
return cell
}
}
The first class that is directly subclassing the from above MyCommonTableController
//In here we just have to know the data and set the infoList from parent
class TheTableViewController: MyCommonTableController {
let defaultList = ["Data1","Data2","Data3"] //....etc
override func viewDidLoad() {
super.viewDidLoad()
//this is were I will set those
infoList = defaultList
//reload the table
tableView.reloadData()
}
}
The second class that is directly subclassing the from above MyCommonTableController. Same process goes here
class TheSecondTableViewController: MyCommonTableController {
let defaultList = ["List1","List2","List3"] //....etc
override func viewDidLoad() {
super.viewDidLoad()
//this is were I will set those
infoList = defaultList
//reload the table
tableView.reloadData()
}
}
And now you are not repeating and table methods. You can also get the reference of table and use in your norma table view
#IBOutlet weak var theTable: UITableView!
let defaultList = ["List1","List2","List3"] //....etc
let commonTable = MyCommonTableController()
// MARK: - LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
commonTable.infoList = defaultList
commonTable.tableView = theTable
}

NSManagedObject has no member 'allObjects'

In my code I have an issue that reads "Value of type 'NSManagedObject' has no member 'allObjects' ". What would I need to include in my code to make the allObjects reference work? I am watching this tutorial on coding this simple app that lists jokes using table views. Thanks in advance!
import UIKit
class jokesViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
var collection: Collection?
var jokes = [Joke]()
override func viewDidLoad() {
super.viewDidLoad()
self.jokes = self.collection?.jokes?.allObjects as! [Joke]
self.tableView.delegate = self
self.tableView.dataSource = self
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.jokes.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let joke = self.jokes[indexPath.row]
cell.textLabel?.text = joke.title
return cell
}
}

Resources