-5

I have created a Form , in which I am using Textfields and TextField Dropdown. While I am scrolling the TableView textfields values got lost and textfield dropdown values set to default automatically.

Here is my code :

    enum TextFieldTags:Int {
        case ProspectName = 10, VisitDate, VisitType, Industry, Source, DissSummary, Requirements, FollowUpDate, AnticipatedDealValue, Probability, ExpectedClosingDate, Status, NextStep, Emp, Rev, AddressLine1, AddressLine2, Country, States, City, Zip, Mobile,Fax
    }

    var prospectName:String?, visitDate:String? , visitType:String?, industry:String?, source:String?, dissSummary:String?, requirements:String?, followUpDate:String?, anticipatedDealValue:String?, probability:String?, expectedClosingDate:String?, status:String?, nextStep:String?, emp:String?, rev:String?, addressLine1:String?, addressLine2:String?, country, statesVal:String?, cityVal:String?, zip:String?, mobile:String?,fax:String?

    var currentLeadMaster:WizLeadMaster?

    // MARK: - Section Data Structure

    struct Section {
        var name: String!
        var options: [Any]!
        var collapsed: Bool!
        var optionItem:[Any]!
        var icon:UIImage!


        init(name: String, options: [Any], collapsed: Bool = false,optionItem:[Any],icon:UIImage) {

            self.name = name
            self.options = options

            self.collapsed = collapsed

            self.optionItem = optionItem
            self.icon = icon


        }
    }

    // MARK: - Properties

    @IBOutlet weak var tblLeadDetail:UITableView?

    var dataSource:NSArray  = NSArray(objects: "Lead Summary","Address","Products","Contacts","Attachment","Follow Up","Remarks")

    var sections = [Section]()

    lazy var visitArr:NSArray = {

        let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMVisittype)

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizLookUp

            let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)

        }
        return optionsArray as NSArray
    }()


    lazy var leadStatus:NSArray = {

        let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMLeadStatus)

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizLookUp

            let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)

        }
        return optionsArray as NSArray
    }()


    lazy var leadSource:NSArray = {

        let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMLeadsource)

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizLookUp

            let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)

        }
        return optionsArray as NSArray
    }()


    lazy var industries:NSArray = {

        let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMCustomerType)

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizLookUp

            let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)
        }
        return optionsArray as NSArray
    }()

    lazy var countries:NSArray = {

        let visitTypes = Handler.countriesList()

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizCountryList

            let dict = ["system":(visitModel.lable! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)

        }
        return optionsArray as NSArray
    }()

    lazy var states:NSArray = {

        let visitTypes = Handler.fetchLookUpOftype(type: LookUpType.enum_cRMTerritory)

        var optionsArray = NSMutableArray(capacity: 0)

        for visitType in visitTypes {

            let visitModel = visitType as! WizLookUp

            let dict = ["system":(visitModel.system! as String),"value":(visitModel.value! as String)]

            optionsArray.add(dict as NSDictionary)

        }
        return optionsArray as NSArray
    }()



    func setStatesForCountry(_ country:String) -> Void{



    }


    func filterValue(_ arr:NSArray,key:String) -> Any {

        let predicate = NSPredicate(format: "self == %@", key)
        let filteredArr = arr.filtered(using: predicate)

        if (filteredArr.count == 0) {
            return ""
        }

        return filteredArr[0]
    }

    // MARK: - ViewDidLoad

    override func viewDidLoad() {

        super.viewDidLoad()

        let barButtonItem = UIBarButtonItem(image:UIImage(named:"save1") , style: UIBarButtonItemStyle.done, target: self, action: #selector(saveLeadInfo))

        navigationItem.rightBarButtonItem = barButtonItem

        sections = [

            Section(name: "Lead Summary", options: [["title":"Prospect Name","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.customer_name as Any,"tag":TextFieldTags.ProspectName.rawValue],
                                                    ["title":"Visit Date","type":"date","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.visited_date as Any,"tag":TextFieldTags.VisitDate.rawValue],
                                                    ["title":"Visit Type","type":"dropdown","options":visitArr.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.VisitType.rawValue],
                                                    ["title":"Industry","type":"dropdown","options":industries.value(forKeyPath: "system"),"value":filterValue(industries.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.type)!),"tag":TextFieldTags.Industry.rawValue],
                                                    ["title":"Source","type":"dropdown","options":leadSource.value(forKeyPath: "system"),"value":filterValue(leadSource.value(forKeyPath: "value") as! NSArray , key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.source)!),"tag":TextFieldTags.Source.rawValue],
                                                    ["title":"Discussion Summary","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.summary_disc as Any,"tag":TextFieldTags.DissSummary.rawValue],
                                                    ["title":"Requirements","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.requirements as Any ,"tag":TextFieldTags.Requirements.rawValue],
                                                    ["title":"Follow-Up Date","type":"date","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.followup_date as Any,"tag":TextFieldTags.FollowUpDate.rawValue],
                                                    ["title":"Anticipated Deal Value","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.anticipated_deal_value as Any,"tag":TextFieldTags.AnticipatedDealValue.rawValue],
                                                    ["title":"Probabilty","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.probability as Any,"tag":TextFieldTags.Probability.rawValue],
                                                    ["title":"Expected Closing Date","type":"date","value":currentLeadMaster?.expected_closing_date as Any,"tag":TextFieldTags.ExpectedClosingDate.rawValue],
                                                    ["title":"Status","type":"dropdown","options":leadStatus.value(forKeyPath: "system"),"value":filterValue(leadStatus.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.status)!),"tag":TextFieldTags.Status.rawValue],
                                                    ["title":"Next Step","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.next_activity_planned as Any,"tag":TextFieldTags.NextStep.rawValue],
                                                    ["title":"Emp","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.no_of_emp as Any,"tag":TextFieldTags.Emp.rawValue],
                                                    ["title":"Rev","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.annual_revenue as Any,"tag":TextFieldTags.Rev.rawValue]], collapsed: true, optionItem: [],icon:UIColor.clear.getImage(size: CGSize(width: 30, height: 30))),
            Section(name: "Address", options: [["title":"Address Line 1","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline1 as Any ,"tag":TextFieldTags.AddressLine1.rawValue],
                                               ["title":"Address Line 2","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.AddressLine2.rawValue],
                                               ["title":"Select Country","type":"dropdown","options":countries.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.Country.rawValue],
                                               ["title":"Select States","type":"dropdown","options":visitArr.value(forKeyPath: "system") as! Array<String>,"value":filterValue(visitArr.value(forKeyPath: "value") as! NSArray, key: ((currentLeadMaster == nil) ? "":currentLeadMaster?.visit_type)!),"tag":TextFieldTags.States.rawValue],
                                               ["title":"Select City","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.City.rawValue],
                                               ["title":"Zip Code","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Zip.rawValue],
                                               ["title":"Mobile","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Mobile.rawValue],
                                               ["title":"Fax","type":"input","value":(currentLeadMaster == nil) ? "":currentLeadMaster?.addressline2 as Any,"tag":TextFieldTags.Fax.rawValue]
                                                    ], collapsed: true, optionItem: [],icon:UIColor.clear.getImage(size: CGSize(width: 30, height: 30))),
            Section(name: "Product", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "add")!),
            Section(name: "Contacts", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "add")!),
            Section(name: "Attachment", options: [], collapsed: true, optionItem: [],icon:UIImage.init(named: "attach")!),
        ]

        let headerNib = UINib(nibName: "WizHeaderView", bundle: nil)
        tblLeadDetail?.register(headerNib, forHeaderFooterViewReuseIdentifier: "headerLeads")

        let textInputCell = UINib(nibName: "TextInputCell", bundle: nil)
        tblLeadDetail?.register(textInputCell, forCellReuseIdentifier: "textinputcell")

        let dropDownInputCell = UINib(nibName: "DropDownInputCell", bundle: nil)
        tblLeadDetail?.register(dropDownInputCell, forCellReuseIdentifier: "dropDownInputCell")

        let dropDownDateCell = UINib(nibName: "DropDownDateCell", bundle: nil)
        tblLeadDetail?.register(dropDownDateCell, forCellReuseIdentifier: "dropDownDateCell")

        tblLeadDetail?.reloadData()

    }


    func saveLeadInfo() -> Void {

    }

    // MARK: - TableView Delegates & Datasource

    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        let optionsArray = sections[section].options

        return optionsArray!.count
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let optionsArray = sections[indexPath.section].options

        let dict = optionsArray?[indexPath.row] as! Dictionary<String,Any>

        if (dict["type"] as! String  == "dropdown") {

            let cell = tableView.dequeueReusableCell(withIdentifier: "dropDownInputCell") as! DropDownInputCell


            cell.txtInput.isOptionalDropDown = false
            cell.txtInput.itemList = dict["options"] as! [String]
            cell.lblText.text = dict["title"] as? String

            cell.txtInput.selectedItem = dict["value"] as? String


            cell.txtInput.tag = (dict["tag"] as? NSInteger)!
            cell.backgroundColor = UIColor.clear
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            cell.delegate = self
            return cell
        }
        else if (dict["type"] as! String  == "input") {

            let cell = tableView.dequeueReusableCell(withIdentifier: "textinputcell") as! TextInputCell
            cell.lblText.text = dict["title"] as? String
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            cell.backgroundColor = UIColor.clear
            cell.txtInput.text = dict["value"] as? String
             cell.txtInput.tag = (dict["tag"] as? NSInteger)!
            cell.delegate = self
            return cell
        }
        else{

            let cell = tableView.dequeueReusableCell(withIdentifier: "dropDownDateCell") as! DropDownDateCell
            cell.lblText.text = dict["title"] as? String
            cell.txtInput.dropDownMode = IQDropDownMode.datePicker

            if dict["value"] as? String == "" {
               cell.txtInput.setDate(Date(), animated: true)
            }
            else{
               cell.txtInput.selectedItem = dict["value"] as? String
            }

            cell.txtInput.tag = (dict["tag"] as? NSInteger)!
            cell.selectionStyle = UITableViewCellSelectionStyle.none
            cell.backgroundColor = UIColor.clear
            cell.delegate = self
            return cell
        }

    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
//        if indexPath.row == 0 {
//            performSegue(withIdentifier: "leadsummary", sender:nil)
//        }
//        else{
//            performSegue(withIdentifier: "leadaddress", sender:nil)
//        }
    }


    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerLeads") as? WizHeaderView ?? WizHeaderView(reuseIdentifier: "headerLeads")

        header.delegate = self

        header.lblLeadSummary.text = sections[section].name
        header.btnArrowButton.setImage(sections[section].icon, for: UIControlState.normal)
        header.setCollapsed(sections[section].collapsed)

        header.section = section

        return header
    }



    func toggleSection(_ header: WizHeaderView, section: Int) {

        let collapsed = !sections[section].collapsed

        // Toggle collapse
        sections[section].collapsed = collapsed
        header.setCollapsed(collapsed)

        // Adjust the height of the rows inside the section
        tblLeadDetail?.beginUpdates()
        for i in 0 ..< sections[section].options.count {
            tblLeadDetail?.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
        }
        tblLeadDetail?.endUpdates()
    }


    @IBAction func placeOrder(_ sender: Any) {

        let placeOrder = MainStoryBoard.instantiateViewController(withIdentifier: "PlaceOrder")
        navigationController?.pushViewController(placeOrder, animated: true)
    }


    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 35.0
    }


    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 10.0
    }


    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return sections[(indexPath as NSIndexPath).section].collapsed! ? 0 : 70.0
    }


    func cellTextField(_with TextField: IQDropDownTextField, didSelectItem item: String?) {

        switch TextField.tag {
            case TextFieldTags.VisitType.rawValue:
                 visitType = item
            break
            case TextFieldTags.Industry.rawValue:
                industry = item
            break
            case TextFieldTags.Source.rawValue:
                source = item
            break
            case TextFieldTags.Status.rawValue:
                status = item
            break
            case TextFieldTags.Country.rawValue:
                country = item
            break
            case TextFieldTags.States.rawValue:
                statesVal = item
            break
            default: break
        }
    }


    func cellTextFieldDidEndEditing(_with textField: UITextField) {

        switch textField.tag {
        case TextFieldTags.ProspectName.rawValue:
            prospectName = textField.text
            break
        case TextFieldTags.DissSummary.rawValue:
            dissSummary = textField.text
            break
        case TextFieldTags.Requirements.rawValue:
            requirements = textField.text
            break
        case TextFieldTags.AnticipatedDealValue.rawValue:
            anticipatedDealValue = textField.text
            break
        case TextFieldTags.Probability.rawValue:
            probability = textField.text
            break
        case TextFieldTags.NextStep.rawValue:
            nextStep = textField.text
            break
        case TextFieldTags.Emp.rawValue:
            emp = textField.text
            break
        case TextFieldTags.Rev.rawValue:
            rev = textField.text
            break
        case TextFieldTags.AddressLine1.rawValue:
            addressLine1 = textField.text
            break
        case TextFieldTags.AddressLine2.rawValue:
            addressLine2 = textField.text
            break
        case TextFieldTags.City.rawValue:
            cityVal = textField.text
            break
        case TextFieldTags.Mobile.rawValue:
            mobile = textField.text
            break
        case TextFieldTags.Fax.rawValue:
            fax = textField.text
            break
        case TextFieldTags.Zip.rawValue:
            zip = textField.text
            break
        default: break

        }

    }


    func stringFromDate(_ date:Date) -> String {

        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter.string(from: date)
    }


    func cellTextFieldDate(_with textField: IQDropDownTextField, didSelect date: Date?) {

        switch textField.tag {
        case TextFieldTags.VisitDate.rawValue:
            visitDate = stringFromDate(date!)
            break
        case TextFieldTags.FollowUpDate.rawValue:
            followUpDate = stringFromDate(date!)
            break
        case TextFieldTags.ExpectedClosingDate.rawValue:
            expectedClosingDate = stringFromDate(date!)
            break
        default: break

        }

    }
}
extension UIColor {
    func getImage(size: CGSize) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image(actions: { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
        })
    }}
ManiaChamp
  • 849
  • 7
  • 22
  • have you tried overriding `prepareForReuse()` in your `UITableViewCells` and clear their data before dequeuing ?:S – MohyG Jul 27 '17 at 07:53
  • Have you implemented UITextField's delegate method like textFieldDidBeginEditing to store whatever input you have received in particular textfield to your datasource? – Dhaval Dobariya Aug 01 '17 at 05:12

2 Answers2

1

While using UITableView with reusable cell identifier, you have to store input of your UITextField or any other input fields when editing is finished into your data source which you are using to fill all cells. Because reusable cell manage memory itself to draw all your controls, so there are no guaranty about your data remains as it is when you scroll your tableview.

Dhaval Dobariya
  • 171
  • 1
  • 12
0

In this if - else expression

if dict["value"] as? String == "" {
   cell.txtInput.setDate(Date(), animated: true)
} else{
   cell.txtInput.selectedItem = dict["value"] as? String
}

you are setting two different UI elements depending on the dictionary value. As cells are reused those UI states will remain until they are changed the next time.

You have to make sure that every UI element is set to a defined state to avoid unexpected behavior, so you need to set the other UI element, too. For example ([default value] is just a placeholder).

if dict["value"] as? String == "" {
   cell.txtInput.setDate(Date(), animated: true)
   cell.txtInput.selectedItem = [default value]
} else{
   cell.txtInput.setDate([default value], animated: [default value])
   cell.txtInput.selectedItem = dict["value"] as? String
}

If there is no unique default value you have to add properties to the data source to keep the current states of the date and the selected item.

Regarding the text field you have to update the data source after changing the text because in cellForRow the text field is always updated from the data source.

And - as always - don't use NS(Mutable)Array and NS(Mutable)Dictionary in Swift. You throw away the important type information and the mutable collection types are not related to the Swift native types. Finally you can delete all break lines in the switch expressions (except after default). They are redundant in Swift.

vadian
  • 274,689
  • 30
  • 353
  • 361