UICollectionViewCell error - ios

My json data is like that and I'm using alamofire for loading data and objectmapper for mapping.I just try to parsing json data and show it on CollectionView.However Im getting error.
Here is my viewcontroller
import UIKit
import Alamofire
import ObjectMapper
import AlamofireObjectMapper
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return schedules?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = UICollectionViewCell()
cell.textLabel?.text = schedules?[indexPath.row].title
}
#IBOutlet weak var collectionViewData: UICollectionView!
var schedules: [Schedule]?
override func viewDidLoad() {
super.viewDidLoad()
collectionViewData.dataSource = self
collectionViewData.delegate = self
loadData()
}
func loadData() {
let jsonDataUrl = "https://jsonplaceholder.typicode.com/posts"
Alamofire.request(jsonDataUrl).responseJSON { response in
self.schedules = Mapper<Schedule>().mapArray(JSONObject: response.result.value)
self.collectionViewData.reloadData()
}
}
}
Here is my schedule file codes for mapping.
import Foundation
import ObjectMapper
import AlamofireObjectMapper
class Schedule: Mappable {
var userId: String
var id: String
var title: String
var body: String
required init?(map: Map) {
userId = ""
id = ""
title = ""
body = ""
}
func mapping(map: Map) {
userId <- map["userId"]
id <- map["id"]
title <- map["title"]
body <- map["body"]
}
}
When I try to run it I'm getting error like that: Value of type 'UICollectionViewCell' has no member 'textLabel'
I tried to add "textLabel" to viewcontroller but it didn't work.Should I add a new class for CollectionView?

Here is a collectionview cell class you can use that has textLabel
class MyCollectionView: UICollectionViewCell {
var textLabel: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
createViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("Cannot initialize")
}
func createViews() {
textLabel = UILabel(frame: .zero)
textLabel.textAlignment = .center
textLabel.translatesAutoresizingMaskIntoConstraints = false
textLabel.backgroundColor = UIColor.black
textLabel.textColor = UIColor.white
textLabel.font = Font.menuText
contentView.addSubview(textLabel)
let views: [String: Any] = ["label": textLabel]
let lHFormat = "H:|[label]|"
let lVFormat = "V:[label]|"
[lHFormat, lVFormat].forEach { format in
let constraints = NSLayoutConstraint.constraints(withVisualFormat: format,
options: [],
metrics: nil,
views: views)
contentView.addConstraints(constraints)
}
}
You can now register this cell and use it so that you can use textLabel property.

Related

Sending array in protocol

I'm trying to send an array from TableView to another TableView by using a protocol but when I'm trying to show data in the second TableView I got 1 element only in it, not the whole array.
From the model, I'm passing name in ExtendedIngredient array from HomeView to be displayed in the TableView in RecipesDetailsView
As in the above image, the ExtendedIngredient has 10 elements but it only shows 1 "all-purpose flour" and I want to show all 10 items.
Model:
struct Recipes: Codable {
let recipes: [Recipe]
}
struct Recipe: Codable {
let title: String?
let image: String?
let pricePerServing: Double?
let readyInMinutes, servings: Int?
let instructions: String?
let extendedIngredients: [ExtendedIngredient]
}
struct ExtendedIngredient: Codable {
let id: Int?
let aisle, image: String?
let name, original, originalString, originalName: String?
let amount: Double?
let unit: String?
let meta, metaInformation: [String]
}
HomeView:
protocol RecipesDetailsSelectActionDelegate: class {
func recipeDetails(
recipeTitle: String,
recipeImage: String,
recipeInstructions: String,
ingredientsNumber: String,
ingredientsNumbersInt: Int,
ingredientsName: [String]
)
}
class HomeView: UIView {
var recipes: Recipes?
var recipesDetails = [Recipe]()
weak var recipeDetailsViewSelectActionDelegate: RecipesDetailsSelectActionDelegate?
override init( frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
lazy var foodTableView: UITableView = {
let foodTableView = UITableView()
foodTableView.translatesAutoresizingMaskIntoConstraints = false
foodTableView.backgroundColor = .customVeryLightGray()
foodTableView.delegate = self
foodTableView.dataSource = self
foodTableView.register(HomeTableViewCell.self, forCellReuseIdentifier: "HomeTableViewCell")
foodTableView.rowHeight = UITableView.automaticDimension
foodTableView.estimatedRowHeight = 100
foodTableView.showsVerticalScrollIndicator = false
foodTableView.separatorStyle = .none
return foodTableView
}()
}
extension HomeView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
recipeDetailsViewSelectActionDelegate?.recipeDetails(
recipeTitle: recipesDetails[indexPath.row].title ?? "Error",
recipeImage: recipesDetails[indexPath.row].image ?? "Error",
recipeInstructions: recipesDetails[indexPath.row].instructions ?? "Error",
ingredientsNumber: "\(recipesDetails[indexPath.row].extendedIngredients.count)",
ingredientsNumbersInt: recipesDetails[indexPath.row].extendedIngredients.count,
ingredientsName: [(recipesDetails[indexPath.row].extendedIngredients[indexPath.row].name ?? "")]
)
}
}
RecipesDetailsView:
class RecipesDetailsView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
lazy var tableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
tableView.showsVerticalScrollIndicator = false
tableView.separatorStyle = .none
tableView.backgroundColor = .white
tableView.register(NumberOfIngredientsTableViewCell.self, forCellReuseIdentifier: "NumberOfIngredientsTableViewCell")
return tableView
}()
}
extension RecipesDetailsView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NumberOfIngredientsTableViewCell", for: indexPath) as! NumberOfIngredientsTableViewCell
cell.theNameOfIngredient.text = recipeVC.ingredientsName[indexPath.row]
return cell
}
}
HomeViewController:
class HomeViewController: UIViewController {
lazy var mainView: HomeView = {
let view = HomeView(frame: self.view.frame)
view.recipeDetailsViewSelectActionDelegate = self
return view
}()
}
extension HomeViewController: RecipesDetailsSelectActionDelegate {
func recipeDetails(recipeTitle: String, recipeImage: String, recipeInstructions: String, ingredientsNumber: String, ingredientsNumbersInt: Int, ingredientsName: [String]) {
let vc = RecipesDetailsViewController()
vc.recipeTitle = recipeTitle
vc.recipeImage = recipeImage
vc.recipeInstructions = recipeInstructions
vc.ingredientsNumber = ingredientsNumber
vc.ingredientsNumberInt = ingredientsNumbersInt
vc.ingredientsName = ingredientsName
self.show(vc, sender: nil)
}
}
RecipesDetailsViewController:
class RecipesDetailsViewController: UIViewController {
var recipeTitle: String?
var recipeImage: String?
var recipeInstructions: String?
var ingredientsNumber: String?
var ingredientsNumberInt: Int?
var ingredientsName: [String] = []
lazy var mainView: RecipesDetailsView = {
let view = RecipesDetailsView(frame: self.view.frame)
view.backgroundColor = .white
return view
}()
override func loadView() {
super.loadView()
mainView.recipeVC = self
view = mainView
}
}
The problem lies in the following line:
ingredientsName:[(recipesDetails[indexPath.row].extendedIngredients[indexPath.row].name ?? "")]
"extendedIngredients[indexPath.row]" this expression will always return just one object depending upon the selected row.
You might have to do something like:
(recipesDetails[indexPath.row].extendedIngredients.compactMap({$0.name}))

How can I execute the collectionView methods of a class from another one?

I have my class CardSensors which is has a collectionView which is filled with another XIB
class CardSensors: UIView {
#IBOutlet weak var botName: UILabel!
#IBOutlet weak var sensorsCollectionView: UICollectionView!
var sensors = [[String: Any]]()
var viewModel: NewsFeedViewModel! {
didSet {
setUpView()
}
}
func setSensors(sensors: [[String: Any]]){
self.sensors = sensors
}
static func loadFromNib() -> CardSensors {
return Bundle.main.loadNibNamed("CardSensor", owner: nil, options: nil)?.first as! CardSensors
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func setupCollectionView(){
let nibName = UINib(nibName: "SensorCollectionViewCell", bundle: Bundle.main)
sensorsCollectionView.register(nibName, forCellWithReuseIdentifier: "SensorCollectionViewCell")
}
func setUpView() {
botName.text = viewModel.botName
}
}
extension CardSensors: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SensorCollectionViewCell", for: indexPath) as? SensorCell else {
return UICollectionViewCell()
}
cell.dateLabel.text = sensors[indexPath.row]["created_at"] as? String
cell.sensorType.text = sensors[indexPath.row]["type"] as? String
cell.sensorValue.text = sensors[indexPath.row]["value"] as? String
cell.sensorImage.image = UIImage(named: (sensors[indexPath.row]["type"] as? String)!)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sensors.count
}
}
Im creating an object in another class like this but I want this to call the methods of the collectionView for it to load the info.
let sensorView = CardSensors.loadFromNib()
sensorView.sensors = sensores
sensorView.setupCollectionView()
The problem is that the collectionView methods are never being called. What can I do to call them from my other class?
You need to set the data souce
sensorsCollectionView.register(nibName, forCellWithReuseIdentifier: "SensorCollectionViewCell")
sensorsCollectionView.dataSource = self
sensorsCollectionView.reloadData()
Then inside your vc , make it an instance variable
var sensorView:CardSensors!
sensorView = CardSensors.loadFromNib()
sensorView.sensors = sensores
sensorView.setupCollectionView()

NSInvalidArgumentException : Workout_Tracker.QuickAddViewController collectionView:numberOfItemsInSection:]: unrecognized selector sent to instance

I have a class MenuTabs: UIView that corresponds to MenuTabs.xib. I linked them in the identity inspector. In the view is a UICollectionView. I set the UIView as the delegate and datasource for the collection view in storyboard. I'm using the MenuTabs class in a ViewController, but I keep getting this error
'NSInvalidArgumentException', reason: '-[Workout_Tracker.QuickAddViewController collectionView:numberOfItemsInSection:]: unrecognized selector sent to instance 0x7fbbe970a120'
Here are my MenuTabs and QuickAddViewController files
import UIKit
class MenuTabs: UIView {
let workoutTypes = ["", "", "", ""]
let cellId = "cellId"
#IBOutlet weak var contentView: UIView!
#IBOutlet weak var collectionView: UICollectionView!
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if self.subviews.count == 0 {
self.setup()
}
}
func setup() {
Bundle.main.loadNibNamed("MenuTabs", owner: self, options: nil)
guard let content = contentView else { return }
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(content)
}
}
// MARK: - Delegate and Datasource methods for UICollectionView
extension MenuTabs: UICollectionViewDelegate, UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return workoutTypes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = UIColor.red
return cell
}
}
import UIKit
class QuickAddViewController: UIViewController {
enum MuscleGroup: String {
case abs = "Abs"
case arms = "Arms"
case back = "Back"
case calves = "Calves"
case chest = "Chest"
case legs = "Glutes & Legs"
case shoulders = "Shoulders"
}
enum WorkoutType: String {
case bodyWeight = "Body Weight"
case weightTraining = "Weight Training"
case sportsAndRecreation = "Sports & Recreation"
case cardio = "Cardio"
}
#IBOutlet weak var workoutTypesMenu: UIView!
let exercisesData = ExerciseDatabase()
var workoutTypesDictionary = Dictionary<String,Dictionary<String,Array<String>>>()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
workoutTypesDictionary = self.exercisesData.exercisesByWorkoutType
tabBarController?.tabBar.isTranslucent = false
// Load workoutTypesMenu View
if let wtMenu = Bundle.main.loadNibNamed("MenuTabs", owner: self, options: nil)?.first as! MenuTabs? {
workoutTypesMenu.addSubview(wtMenu)
}
}
// MARK: - Get data from ExerciseDatabase.swift
// Get the workout types
func getWorkoutTypes() -> [String] {
var workoutTypesArray : [String] = []
for workoutType in workoutTypesDictionary.keys {
workoutTypesArray.append(workoutType)
}
return workoutTypesArray
}
// Get the list of muscles or options
func getMusclesOrOptions(for workoutType: String) -> [String] {
var musclesOrOptionsArray : [String] = []
let musclesOrOptions = workoutTypesDictionary[workoutType]!.keys
for muscleOrOption in musclesOrOptions {
musclesOrOptionsArray.append(muscleOrOption)
}
return musclesOrOptionsArray
}
// Get the list of exercises
func getExercisesArray(for workoutType: String, for muscleOrOption: String) -> [String] {
var exercisesArray : [String] = []
exercisesArray = workoutTypesDictionary[workoutType]![muscleOrOption]!
return exercisesArray
}
// Get the selected exercise
func getSelectedExercise(in workoutType: String, for muscleOrOption: String, at index: Int) -> String {
var selectedExercise : String = ""
selectedExercise = workoutTypesDictionary[workoutType]![muscleOrOption]![index]
return selectedExercise
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - WorkoutTypesBar and Muscles and Options Bar
// Set up the WorkoutTypes bar and the muscles and option types bar
}
Instead of setting up the delegate and datasource through the nib file, I set them in the init method of MenuTabs.swift
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
setup()
}

Acess uiviewController element from another class

there is this project im working on, but there is a problem with the element in the viewcontroller of my storyboard which i want to change its property from another class!
my first approach was instantiating an object from the viewcontroller in my second class! which returns nil at runtime!
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
// mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
let msvc = mainstampvc()
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
my second approache was instantiate the whole viewcontroller again in my second class which does nothing.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
the whole thing i wanted is when i click on my uicollectionviewcell change the background of one of my MainViewcontroller views. here is all my classes
viewcontroller.swift
import Foundation
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var stampholder: UIView!
#IBAction func TextViewButton(_ sender: Any) {
removerSubViews()
addSubView(ViewName: "text")
}
#IBAction func AViewButton(_ sender: Any) {
removerSubViews()
addSubView(ViewName: "mohr")
}
#IBAction func BorderViewButton(_ sender: Any) {
}
#IBAction func DlViewButton(_ sender: Any) {
}
#IBOutlet weak var holderView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
addSubView(ViewName: "mohr")
let mainstampvc = self.storyboard?.instantiateViewController(withIdentifier: "mainstampvc")
let mainstampview = mainstampvc?.view
mainstampview?.frame = stampholder.frame
stampholder.addSubview((mainstampview)!)
}
func removerSubViews(){
for view in self.holderView.subviews{
view.removeFromSuperview()
}
}
func addSubView(ViewName: String)
{
if let subview = Bundle.main.loadNibNamed(ViewName, owner: self, options: nil)?.first as? UIView {
self.holderView.addSubview(subview);
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
mohrcollectionview.swift
import Foundation
import UIKit
class MohrCollectionViewController: UIView,UICollectionViewDataSource,UICollectionViewDelegate{
var mohrPath: String = ""
var fileManager: FileManager!
var list_images : [String] = []
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fileManager = FileManager.default
let currentDir = Bundle.main.resourcePath
mohrPath = currentDir!
let mohrsPath = try? fileManager.contentsOfDirectory(atPath: mohrPath + "/mohr")
list_images = mohrsPath!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return list_images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collectionView.register(UINib(nibName: "mohrcell", bundle: nil), forCellWithReuseIdentifier: "mohrcell")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mohrcell", for: indexPath) as! mohrCellController
let image = UIImage(named: list_images[indexPath.row])
cell.cellimage.image = image
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let mainstampvc = MainStampVc().storyboard?.instantiateViewController(withIdentifier: "mainstampvc") as? MainStampVc
mainstampvc?.setstampimage(imageURL: list_images[indexPath.row])
}
}
mainstampvc.swift
import Foundation
import UIKit
class MainStampVc: UIViewController{
#IBOutlet weak var stampimage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
setstampimage(imageURL: "golbanafsh.png")
}
public func setstampimage(imageURL: String)
{
stampimage.image = UIImage(named: imageURL)
}
}
any help would be appreciated
2
so here is my code with delegation but still nothing :(
//
// MohrCollectionViewController.swift
// Mohrem
//
// Created by shayan rahimian on 12/18/17.
// Copyright © 2017 shayan rahimian. All rights reserved.
//
import Foundation
import UIKit
class MohrCollectionViewController: UIView,UICollectionViewDataSource,UICollectionViewDelegate,UpdateBackgroundDelegate{
var updatedelegate:UpdateBackgroundDelegate? = nil
func updateBackground(imageURL: String) {
print("mohr update back ground e balaE")
if updatedelegate == nil {
print("no delegate")
}else{
updatedelegate?.updateBackground(imageURL: imageURL)
}
}
var mohrPath: String = ""
var fileManager: FileManager!
var list_images : [String] = []
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fileManager = FileManager.default
let currentDir = Bundle.main.resourcePath
mohrPath = currentDir!
let mohrsPath = try? fileManager.contentsOfDirectory(atPath: mohrPath + "/mohr")
list_images = mohrsPath!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
return list_images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collectionView.register(UINib(nibName: "mohrcell", bundle: nil), forCellWithReuseIdentifier: "mohrcell")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mohrcell", for: indexPath) as! mohrCellController
let image = UIImage(named: list_images[indexPath.row])
cell.cellimage.image = image
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.updateBackground(imageURL: list_images[indexPath.row])
}
}
//
// MainStampvc.swift
// Mohrem
//
// Created by shayan rahimian on 12/19/17.
// Copyright © 2017 shayan rahimian. All rights reserved.
//
import Foundation
import UIKit
protocol UpdateBackgroundDelegate : class {
func updateBackground(imageURL: String)
}
class MainStampVc: UIViewController{
#IBOutlet weak var stampimage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
updateBackground(imageURL: "biggolabi.png")
}
func updateBackground(imageURL: String) {
// update your background in this funcion
print("extension")
print(imageURL)
stampimage.image = UIImage(named: imageURL)
}
}
am i doing anything wrong?
You could pass a UIViewController reference to the MohrCollectionViewController(you should call this MohrCollectionView to avoid confusion) at the time you construct it. Then whenever you need to update the background you call the relevant function on the reference.
class ViewController : UIViewController {
...
override func viewDidLoad() {
...
let view = addSubView(ViewName: "mohr")
view?.vc = self
}
func addSubView(ViewName: String) -> UIView?
{
if let subview = Bundle.main.loadNibNamed(ViewName, owner: self, options: nil)?.first as? UIView {
self.holderView.addSubview(subview);
return subview
}
}
return nil
}
class MohrCollectionView {
func updateVcBackground() {
vc?.updateBackground()
}
var vc : ViewController? = nil
}
A cleaner way to do this is use a delegate. A delegate uses a protocol to define an interface between two classes.
protocol UpdateBackgroundDelegate : class {
func updateBackground()
}
class ViewController : UIViewController, UpdateBackgroundDelegate {
...
override func viewDidLoad() {
...
let view = addSubView(ViewName: "mohr")
view?.updateBackgroundDelegate = self
}
func updateBackground() {
// update your background in this funcion
}
}
class MohrCollectionView {
func updateVcBackground() {
updateBackgroundDelegate?.updateBackground()
}
var updateBackgroundDelegate : UpdateBackgroundDelegate? = nil
}
For making the delegate work do the following:
Declare the delegate first like in Collection View Class
protocol UpdateBackgroundDelegate : class {
func updateBackground(imageURL: String)
}
Create a variable like
var updateDelegate: UpdateBackgroundDelegate?
and paste it below your collectionView class from where you want to trigger changing background colour
In the collection view selection delegate, add this line of code
updateDelegate.updateBackground(imageUrl: yourUrl)
In the View, where colour change has to take place, create your collectionView instance and add this line of code
collectionView.updateDelegate = self
At last add this extension
class ViewController :UpdateBackgroundDelegate {
func updateBackground(imageUrl: yourUrl) {
//write code to load image from url
}
}

Swift: Everything is loading from web in collectionViewCell except image

i put a sliderCollectionViewController in UICollectionViewCell, now everything is loading from web properly without image. but i am not getting any message about error
import UIKit
import Foundation
NSObject
class Description: NSObject {
var id: Int?
var product_id: Int?
var myDescription: String?
var all_images: [String]?
var product_description: String?
}
DescriptionCollectionViewController
class DescriptionCollectionView: UICollectionViewController, UICollectionViewDelegateFlowLayout{
var arrDescription = [Description]()
** Networking Request api **
func loadDescription(){
ActivityIndicator.customActivityIndicatory(self.view, startAnimate: true)
let url = URL(string: .......)
URLSession.shared.dataTask(with:url!) { (urlContent, response, error) in
if error != nil {
print(error ?? 0)
}
else {
do {
let json = try JSONSerialization.jsonObject(with: urlContent!) as! [String:Any]
let myProducts = json["products"] as? [String: Any]
let myData = myProducts?["data"] as? [[String:Any]]
myData?.forEach { dt in
let oProduct = Description()
oProduct.id = dt["id"] as? Int
oProduct.product_id = dt["product_id"] as? Int
oProduct.myDescription = dt["description"] as? String
oProduct.product_description = dt["product_description"] as? String
oProduct.all_images = dt["all_images"] as? [String]
self.arrDescription.append(oProduct)
}
} catch let error as NSError {
print(error)
}
}
DispatchQueue.main.async(execute: {
ActivityIndicator.customActivityIndicatory(self.view, startAnimate: false)
self.collectionView?.reloadData()
})
}.resume()
}
let descriptionCellId = "descriptionCellid"
override func viewDidLoad() {
super.viewDidLoad()
self.loadDescription()
collectionView?.register(DescriptionCell.self, forCellWithReuseIdentifier: descriptionCellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrDescription.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: descriptionCellId, for: indexPath) as! DescriptionCell
cell.descriptionOb = arrDescription[indexPath.item]
return cell
}
}
DescriptionCollectionViewCell
class DescriptionCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var descriptionOb: Description? {
didSet {
descriptionTextView.text = descriptionOb?.myDescription
couponTextView.text = descriptionOb?.product_description
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
}
let cellId = "cellId"
lazy var slideCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.clear
return cv
}()
let descriptionTextView: UITextView = {
let textview = UITextView()
textview.text = "Description is the pattern of development "
return textview
}()
let couponTextView: UITextView = {
let textview = UITextView()
textview.text = "Description is the pattern of development "
return textview
}()
func setupCell() {
slideCollectionView.dataSource = self
slideCollectionView.delegate = self
slideCollectionView.isPagingEnabled = true
slideCollectionView.register(SlideCell.self, forCellWithReuseIdentifier: cellId)
addSubview(slideCollectionView)
addSubview(descriptionTextView)
addSubview(couponTextView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let count = descriptionOb?.all_images?.count{
return count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SlideCell
if let imageName = descriptionOb?.all_images?[indexPath.item]{
cell.imageView.image = UIImage(named: imageName)
}
return cell
}
}
SliderCell
class SlideCell: UICollectionViewCell{
override init(frame: CGRect) {
super.init(frame: frame)
setupCellSlider()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let imageView: CustomImageView = {
let iv = CustomImageView()
iv.contentMode = .scaleAspectFill
iv.image = UIImage(named: "defaultImage3")
iv.backgroundColor = UIColor.green
return iv
}()
func setupCellSlider() {
backgroundColor = .green
addSubview(imageView)
}
}
json web
The problem is that you did:
oProduct.all_images = dt["all_images"] as? [String]
but all_images is not a string, it is a dictionary as you can see in your json.
You have to access the key image of all_images in order to show it properly.
See this:
How to access deeply nested dictionaries in Swift
You can try this:
oProduct.all_images = dt["all_images"]["image"] as? [String]
The value for key all_images is an array of dictionaries. If you want to extract all image values use the flatMap function
if let allImages = dt["all_images"] as? [[String:Any]] {
oProduct.all_images = allImages.flatMap { $0["image"] as? String }
}
But consider that the value for key image is the string representation of an URL.

Resources