如何确保表格视图单元格在第一个选项卡上始终触发?

时间:2019-02-05 15:28:17

标签: ios swift uitableview didselectrowatindexpath

我的桌子表现得很奇怪。我的桌子上有4行。 我第一次访问该表格时,didSelectRowAt使用1个标签,但是当我前后点击8次左右(进出)时,最后4次需要2个标签。

这就是我所拥有的

import UIKit
import SwiftyJSON

class AddDevicesViewController: UIViewController {

    @IBOutlet weak var addDeviceTable: UITableView!
    @IBOutlet weak var doneButton: UIButton!
    @IBOutlet weak var doneButtonWidth: NSLayoutConstraint!

    var profile: Profile?
    var devices: [Device] = []
    var selectedDevices: [Device] = []
    var showOnlyProfileDevices: Bool = false
    var deviceStartList = [String]()
    var selectedIndexPath : IndexPath!
    var disableBackNavigation : Bool = false
    var selectedRow : Int = 0
    var mode : String = "addDevice"

    var radioOff : UIImageView  {
        let imageSize = Constants.IS_SMALLSCREEN ? 25 : 30
       let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: imageSize, height: imageSize))

        imgView.clipsToBounds = true
        imgView.image = UIImage(named: "radio_off")
        return imgView
    }

    var radioOn : UIImageView  {
        let imageSize = Constants.IS_SMALLSCREEN ? 25 : 30
        let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: imageSize, height: imageSize))

        imgView.clipsToBounds = true
        imgView.contentMode = .scaleToFill
        imgView.image = UIImage(named: "ok")
        imgView.tintColor = UIColor.blue
        return imgView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let backIndicator = UIBarButtonItem(image: UIImage(named: "backArrow"), style: UIBarButtonItem.Style.plain, target: self, action: #selector(goBack))
        backIndicator.tintColor = UIColor.white

        self.navigationItem.leftBarButtonItem = backIndicator
        addDeviceTable.delegate = self
        addDeviceTable.dataSource = self

        //Add rounded corner to Done button
        if Constants.IS_SMALLSCREEN {
            doneButtonWidth.constant = 200
        }
        doneButton.layer.cornerRadius = 5.0

        //Add target action for Done button
        doneButton.addTarget(self, action: #selector(donePressed), for: .touchUpInside)

        addDeviceTable.refreshControl = UIRefreshControl()
        addDeviceTable.refreshControl?.addTarget(self, action: #selector(refreshData), for: .valueChanged)

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationItem.title = self.title
        self.tabBarItem.title = "Profile"

        if !showOnlyProfileDevices {
            self.navigationItem.title = "Add device to \((profile?.name)!)"
        } else {
            self.navigationItem.title = "\((profile?.name)!)'s devices"
        }
        doneButton.isHidden = showOnlyProfileDevices

        //Disable back navigation when new profile is added and this screen is shown
        self.navigationItem.leftBarButtonItem?.isEnabled = !disableBackNavigation

        selectedDevices.removeAll()
        profile?.assignedDevices.forEach { (device) in
            if !isDeviceQuarantined(device.mac ?? "") {
                selectedDevices.append(device)
            }
        }

        for index in 0..<(selectedDevices.count) {
            deviceStartList.append(selectedDevices[index].mac!)
        }
    }

    @objc func goBack(_ sender: Any) {
        navigationController?.popViewController(animated: true)
    }

    func loadDeviceNamesAndACL() {
        devices.forEach { (device) in
            APIService.shared.getDeviceName(cpe: (loginAccount.cpe?.mac)!, vlan: "100", mac: device.mac!, caller: self)
            APIService.shared.getCpeDeviceACL(cpe: (loginAccount.cpe?.mac)!, vlan: "100", device: device.mac!, caller: self)
        }
    }

    @objc func refreshData() {

        let id = self.profile?.id
        let cpe = self.profile?.cpe

        if !showOnlyProfileDevices {
            APIService.shared.cpeDevices(cpe: cpe!, caller: self)
        } else {
            APIService.shared.profileDevices(cpe: cpe!,profileId: id!, caller: self)
        }
    }


    @objc func donePressed(_ sender: Any) {
        //Move back to Profile Detail.
        if !showOnlyProfileDevices  {
            profile?.assignedDevices = selectedDevices
        }

        var deviceEndList = [String]()
        for index in 0..<(selectedDevices.count) {
            deviceEndList.append(selectedDevices[index].mac!)
        }

        //Delete if uncheck
        for index in 0..<(self.deviceStartList.count) {
            if deviceEndList.contains(deviceStartList[index]){
            }else {

                let id = self.profile?.id
                let cpe = self.profile?.cpe
                let deviceMac = deviceStartList[index]

                APIService.shared.removeDeviceFromProfile(cpe: cpe!,profileId: id!, deviceMac: deviceMac, caller: self)
            }
        }

        for index in 0..<(selectedDevices.count) {

            let id = self.profile?.id
            let cpe = self.profile?.cpe
            let deviceMac = selectedDevices[index].mac

            APIService.shared.addDeviceToProfile(cpe: cpe!,profileId: id!, deviceMac: deviceMac!, caller: self)

        }

        navigationController?.popToRootViewController(animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDeviceDetail" {

            let destVC = segue.destination as! DeviceDetailViewController
            if let _ = addDeviceTable.indexPathForSelectedRow {
                destVC.device = devices[selectedRow]
            }
        }
    }


}

extension AddDevicesViewController : UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return devices.count
    }

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

        let cell = tableView.dequeueReusableCell(withIdentifier: "devicecell", for: indexPath) as! DeviceTableViewCell
        let device = devices[indexPath.row]

        cell.rowNumber = indexPath.row

        if device.access ?? false {
            cell.playpauseButton?.setImage(UIImage(named: "play"), for: .normal)
        } else {
            cell.playpauseButton?.setImage(UIImage(named: "pause"), for: .normal)
        }

        cell.playpauseButton?.isEnabled = true

        cell.delegate = self

        cell.deviceName?.text = getDeviceName(device: device)
        cell.deviceMAC?.text = device.status?.ip

        if device.status?.state == "active" {
            cell.deviceStatus?.setImage(UIImage(named: "greendot"), for: .normal)
        } else {
            cell.deviceStatus?.setImage(UIImage(named: "reddot"), for: .normal)
        }
        cell.deviceStatus.layer.cornerRadius = 5.0

        let deviceImageName = getDeviceIcon(device)

        cell.deviceImageView?.image = UIImage(named: deviceImageName!)

        if !showOnlyProfileDevices {
            if let image = getProfileImage(device: device) {
                cell.profileImageView.image = image
                cell.profileImageView.isHidden = false
            } else {
                cell.profileImageView.isHidden = true
            }
        } else {
            cell.profileImageView.isHidden = true
        }

        if !showOnlyProfileDevices {
            let assignedDevices = profile?.assignedDevices
            let matchingIndex = assignedDevices?.index(where: { (thisDevice) -> Bool in
                return thisDevice.mac == device.mac
            })
            cell.isSelected = (matchingIndex != nil)
            cell.accessoryView = cell.isSelected ? radioOn : radioOff
        }

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath) as? DeviceTableViewCell

        selectedRow = indexPath.row

        consoleLog("Click")

        if !showOnlyProfileDevices  {
            cell?.accessoryView = radioOn
            cell?.isSelected = true

            cell?.profileImageView.image = profileImages[profile?.name ?? "Unknown"]
            cell?.profileImageView.isHidden = false

            //Add to the list
            let device = devices[indexPath.row]
            if selectedDevices.index(where: { (dev) -> Bool in
                return dev.mac == device.mac
            }) != nil {
                //Don't add again
            } else {
                selectedDevices.append(device)
            }
        } else {
            performSegue(withIdentifier: "showDeviceDetail", sender: self)
        }
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath) as? DeviceTableViewCell

        if !showOnlyProfileDevices {
            cell?.accessoryView = radioOff
            cell?.isSelected = false

            //Remove from list
            let device = devices[indexPath.row]

            if let image = getProfileImage(device: device) {
                if cell?.profileImageView.image == image {
                    cell?.profileImageView.image = nil
                    cell?.profileImageView.isHidden = true
                } else {
                    cell?.profileImageView.image = image
                    cell?.profileImageView.isHidden = false
                }
            } else {
                cell?.profileImageView.isHidden = true
            }

            if let index = selectedDevices.index(where: { (dev) -> Bool in
                return device.mac == device.mac
            }) {
               selectedDevices.remove(at: index)
            }
        } else {
            cell?.profileImageView.isHidden = true
        }
    }

    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        var configuration : UISwipeActionsConfiguration!

        let deleteAction = self.contextualDeleteAction(forRowAtIndexPath: indexPath)
        let editAction = self.contextualEditAction(forRowAtIndexPath: indexPath)

        if showOnlyProfileDevices {
            configuration = UISwipeActionsConfiguration(actions: [deleteAction, editAction])
        } else {
            configuration = UISwipeActionsConfiguration(actions: [])
            configuration.performsFirstActionWithFullSwipe = false
        }

        return configuration
    }

    func contextualDeleteAction(forRowAtIndexPath: IndexPath) -> UIContextualAction {
        selectedIndexPath = forRowAtIndexPath

        let action = UIContextualAction(style: .normal, title: "Delete") { (contextAction: UIContextualAction, sourceView: UIView, completionHandler: (Bool) -> Void) in

            let alertController = UIAlertController(title: "Warning", message: "Delete this device?", preferredStyle: UIAlertController.Style.alert)
            alertController.addAction(UIAlertAction(title: "Yes", style: UIAlertAction.Style.default, handler: { (UIAlertAction) in
                //Call API Service to delete device from Profile
                let deviceMac = self.devices[self.selectedIndexPath.row].mac

                self.devices.remove(at: self.selectedIndexPath.row)
                APIService.shared.deleteDeviceFromNetwork(cpe: (loginAccount.cpe?.mac)!, vlan: "100", deviceMac: deviceMac ?? "", caller: self)
                OperationQueue.main.addOperation {
                    self.addDeviceTable.reloadData()
                }
            }))

            alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: { (UIAlertAction) in
                self.addDeviceTable.reloadData()
            }))

            self.present(alertController, animated: true)
        }

        action.backgroundColor = .red

        return action
    }

    func contextualEditAction(forRowAtIndexPath: IndexPath) -> UIContextualAction {
        selectedIndexPath = forRowAtIndexPath

        let cpe = loginAccount.cpe?.mac ?? ""
        let deviceMac = devices[selectedIndexPath.row].mac ?? ""
        let deviceOldName = getDeviceName(device: devices[selectedIndexPath.row])
        var deviceNewName : String?

        let action = UIContextualAction(style: .normal, title: "Edit") { (contextAction: UIContextualAction, sourceView: UIView, completionHandler: (Bool) -> Void) in

            let alertController = UIAlertController(title: "Edit Device Name", message: "", preferredStyle: UIAlertController.Style.alert)
            alertController.addTextField(configurationHandler: { (deviceName) in
                deviceName.text = deviceOldName
            })
            alertController.addAction(UIAlertAction(title: "Save", style: UIAlertAction.Style.default, handler: { (UIAlertAction) in
                deviceNewName = alertController.textFields?[0].text ?? deviceOldName
                if (deviceNewName != deviceOldName) || (deviceNewName != "") {
                    self.devices[self.selectedIndexPath.row].deviceName = deviceNewName
                    //Call API Service to rename the device
                    APIService.shared.updateDeviceName(cpe: cpe, vlan: "100", mac: deviceMac, name: deviceNewName!, caller: self)
                    OperationQueue.main.addOperation {
                        self.addDeviceTable.reloadData()
                    }
                }
            }))

            alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: { (UIAlertAction) in
                self.addDeviceTable.reloadData()
            }))

            self.present(alertController, animated: true)
        }

        action.backgroundColor = .blue

        return action
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return Constants.IS_SMALLSCREEN ? 68 : 80
    }
}

extension AddDevicesViewController: DeviceTableViewCellDelegate {

    func updateACL(_ row : Int, _ flag : Bool) {

        if devices[row].status?.state == "active" {
            devices[row].access = flag
        }

        let cpe = (loginAccount.cpe?.mac)!
        let deviceMac = devices[row].mac
        let vlan = "100"

        addDeviceTable.reloadRows(at: [IndexPath(row: row, section: 0)], with: .none)

        APIService.shared.updateCpeDeviceACL(cpe: cpe,vlan: vlan, device: deviceMac!, portalUrl: "", acl: flag, caller: self)

    }

}

extension AddDevicesViewController : APIServiceCallbackDelegate {
    func processData(_ reqParams: [String: Any], _ data: Data?, _ response: URLResponse?, _ error: Error?) {

        OperationQueue.main.addOperation {
            self.addDeviceTable.refreshControl?.endRefreshing()
        }

        if error != nil {
            OperationQueue.main.addOperation {
                print("Error: ", error.debugDescription)
                if self.addDeviceTable.refreshControl?.isRefreshing == true {
                    self.addDeviceTable.refreshControl?.endRefreshing()
                }
            }
            return
        }

        let json = JSON(data as Any)

        if !checkHttpResponse(response) {
            if let msg = json["message"].string {
                OperationQueue.main.addOperation {
                    print("Message: ", msg)
                    if self.addDeviceTable.refreshControl?.isRefreshing == true {
                        self.addDeviceTable.refreshControl?.endRefreshing()
                    }
                }
            }


        } else {
            let reqType = reqParams["reqType"] as! RequestType

            switch reqType {

            case .addDeviceToProfile:

                print("Added Device to Profile successfully")

            case .removeDeviceFromProfile:

                print("Removed Device from Profile successfully")

            case .deleteDeviceFromNetwork:
                print("Removed Device from Network successfully")

            case .cpeDevices:
                loginAccount.cpeDevices = parseCpeDevices(json)

                devices.removeAll()
                loginAccount.cpeDevices.forEach { (device) in
                    devices.append(device)
                }
                OperationQueue.main.addOperation {
                    self.loadDeviceNamesAndACL()
                }
            case .profileDevices:
                profile?.assignedDevices = parseProfileDevices(json)

                devices.removeAll()
                profile?.assignedDevices.forEach({ (device) in
                    devices.append(device)
                })
                OperationQueue.main.addOperation {
                    self.loadDeviceNamesAndACL()
                }
            case .getDeviceName:
                let deviceMac = reqParams["mac"] as! String
                let name = json["name"].string

                if let index = devices.firstIndex(where: { (dev) -> Bool in
                    return dev.mac == deviceMac
                }) {
                    devices[index].deviceName = name
                    OperationQueue.main.addOperation {
                        self.addDeviceTable.reloadData()
                    }
                }
            case .getCpeDeviceACL:
                let access = parseCpeDeviceACL(json)
                if let index = devices.index(where: { (device) -> Bool in
                    return device.mac == (reqParams["device"] as! String)
                }) {
                    devices[index].access = access
                    OperationQueue.main.addOperation {
                        self.addDeviceTable.reloadData()
                    }
                }

            case .updateCpeDeviceACL:
                let _ = parseCpeDeviceACL(json)
            default:
                break
            }
        }

    }
}

我在做什么我应该避免的事情?

0 个答案:

没有答案