Search code examples
iosswiftfor-loopseguexcode9

onClick event in a for loop (Swift) not working


Data sharing between two view controllers by using segue is not working in for loop. I am using Xcode9 and Swift

swift4

ViewController.swift

import UIKit
import SwiftyJSON
import Alamofire

class ViewController: UIViewController {

var distnames = [String]()
var distcodes = [String]()
var data1: [AnyObject] = []
var values = [String]()
var values1 = [String]()
var current_arr :[String] = []
var ofcnames = " ";
var ofccodes = " ";
var code = " ";

var testtext = "";
var id = "";
var tiTle = "";
var releaseYear = "";

@IBOutlet weak var Verticalstackview: UIStackView!
@IBOutlet weak var scrollview: UIScrollView!
@IBOutlet weak var testlabel: UILabel!
@IBOutlet weak var mainView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    print("code is \(code)")
    self.values = [String]()
    self.values1 = [String]()
    self.ofcnames = "";
    self.ofccodes = "";

    Alamofire.request("https://facebook.github.io/react-native/movies.json")

        .responseJSON { (response) in
            if ((response.result.value) != nil) {
                let jsondata = JSON(response.result.value!)
                // print(jsondata)
                if let da = jsondata["movies"].arrayObject
                {
                    self.data1 = da as [AnyObject]
                    print("resp is \(da) ")

                }

                    print("respcode count is    \(self.data1.count) ")
                    self.Verticalstackview.height(constant: 40)
                    self.mainView.height(constant: CGFloat(40 * self.data1.count))
                    self.scrollview.height(constant: CGFloat(40 * self.data1.count))

                    for distics in self.data1 {
                    if let resp = distics as? NSDictionary {

                        self.id = resp["id"] as! String
                        self.tiTle = resp["title"] as! String
                        self.releaseYear = resp["releaseYear"] as! String

                        let stackView =  UIStackView()
                        stackView.height(constant: 40)
                        stackView.distribution = .fill
                        stackView.alignment = .fill
                        stackView.axis = .horizontal
                        stackView.spacing = 5

                        let lblId = UILabel()
                        lblId .text = "\(self.id)"
                        lblId .font = UIFont(name: "verdana", size: 15.0)
                        lblId .textAlignment = .center
                        lblId .textColor = .gray
                        lblId .numberOfLines = 0
                        lblId .width(constant: 55)

                        let lbltiTle   = UILabel()
                        lbltiTle.text = "\(self.tiTle)"
                        lbltiTle.font = UIFont(name: "verdana", size: 15.0)
                        lbltiTle.textAlignment = .left
                        lbltiTle.textColor = .black
                        lbltiTle.numberOfLines = 0
                        lbltiTle.width(constant: 120)
                        let tap = UITapGestureRecognizer.init(target:self,action: #selector(self.tapFunction) )
                        lbltiTle.isUserInteractionEnabled = true
                        lbltiTle.addGestureRecognizer(tap)
                        self.testtext = lbltiTle.text!

                        let lblRYear = UILabel()
                        lblRYear.text = "\(self.releaseYear)"
                        lblRYear.font = UIFont(name: "verdana", size: 15.0)
                        lblRYear.textAlignment = .right
                        lblRYear.textColor = .black
                        lblRYear.numberOfLines = 0
                        lblRYear.width(constant: 100)

                        stackView.addArrangedSubview(lblId )
                        stackView.addArrangedSubview(lbltiTle)
                        stackView.addArrangedSubview(lblRYear)


                        self.Verticalstackview.addArrangedSubview(stackView)

                    }
                }
            }
            print(self.values1)
    }
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
@objc func tapFunction(sender:UITapGestureRecognizer) {
    print("tap working")
    self.performSegue(withIdentifier: "Segue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let secondcntroller = segue.destination as! SecondViewController
    secondcntroller.mystring = self.testtext
}
}
 extension UIView{
func height(constant : CGFloat){
    setConstraint(value: constant,attribute: .height)
}
func width(constant : CGFloat){
    setConstraint(value: constant,attribute: .width)
}
private func removeConstraint(attribute: NSLayoutAttribute){
    constraints.forEach {
        if $0.firstAttribute == attribute
        {
            removeConstraint($0)
        }
    }
}
private func setConstraint(value:CGFloat ,attribute: NSLayoutAttribute){
    removeConstraint(attribute: attribute)
    let Constraint =
        NSLayoutConstraint(item: self,
                           attribute: attribute,
                           relatedBy: NSLayoutRelation.equal,
                           toItem: nil,
                           attribute: NSLayoutAttribute.notAnAttribute,
                           multiplier: 1,
                           constant: value)
    self.addConstraint(Constraint)
}

}

SecondViewController.swift

import UIKit

class SecondViewController: UIViewController {
@IBOutlet weak var label: UILabel!

var mystring = String()
override func viewDidLoad() {
    super.viewDidLoad()
    label.text=mystring
}
}

When I click the movie name text, I want that to be displayed on the second view using segue. https://i.sstatic.net/dvm8j.png But always it displays the last movie name. Please assist me sorting this issue.
https://i.sstatic.net/UqyqM.png


Solution

  • You should update your tapFunction

    @objc func tapFunction(sender:UITapGestureRecognizer) {
        let touchedLabel = sender.view as! UILabel
        self.testtext = touchedLabel.text
        self.performSegue(withIdentifier: "Segue", sender: self)
    }
    

    Hope it helps

    EDIT

    Now as you wants to pass the multiple values, what you can do is:

    First change your for in loop from

    for distics in self.data1 {
    

    To

    for (index, distics) in self.data1.enumerated() {
    

    Now, set the tag to your label below this line

    lbltiTle.addGestureRecognizer(tap)
    // Add tag to your label
    lbltiTle.tag = index
    //**TIP: You should name the variables in camelCase format**
    

    Now modify your function, that detects the tap on label and get the object with index being passed with the label in form of it's tag. Modify it to.

    @objc func tapFunction(sender:UITapGestureRecognizer) {
        let touchedLabel = sender.view as! UILabel
        let touchedIndex = touchedLabel.tag
        let selectedDict: NSDictionary = self.data1[touchedIndex]
        print("selectedDict:\(selectedDict)")
        self.performSegue(withIdentifier: "Segue", sender: self)
    }
    

    You can print the required values from it.

    NOTE: For the pure swift approach, you should Avoid using NSDictionary, better use [String: Any] which is a key value pair.

    Hope it helps