UITableViewCell在滚动时重复并丢失其数据

时间:2017-07-23 04:16:53

标签: ios uitableview swift3 reuseidentifier

我创建了一个Form,我正在使用Textfields和TextField Dropdown。当我滚动TableView时,文本字段值丢失,文本字段下拉值自动设置为默认值。

这是我的代码:

    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))
        })
    }}

2 个答案:

答案 0 :(得分:1)

在使用UITableView with reusable cell identifier时,您必须存储UITextField或任何其他输入字段的输入,当您在用于填充所有单元格的数据源中完成编辑时。因为可重复使用的单元管理内存本身来绘制所有控件,所以当您滚动tableview时,不保证您的数据保持不变。

答案 1 :(得分:0)

在此if - else表达式

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

根据字典值设置两个不同的 UI元素。 在重复使用单元格时,这些UI状态将保留,直到下次更改为止。

您必须确保将每个 UI元素设置为已定义的状态以避免意外行为,因此您还需要设置其他UI元素。例如([default value]只是占位符)。

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
}

如果没有唯一default value,您必须向数据源添加属性以保持日期和所选项目的当前状态。

关于文本字段,您必须在更改文本后更新数据源,因为在cellForRow中,文本字段始终从数据源更新。

而且 - 一如既往 - 请勿在Swift中使用NS(Mutable)ArrayNS(Mutable)Dictionary。您丢弃了重要的类型信息,并且可变集合类型与Swift本机类型无关。最后,您可以删除break表达式中的所有switch行(default之后除外)。它们在Swift中是多余的。