ping через хост-массив и показать результаты в таблице - PullRequest
0 голосов
/ 02 сентября 2018

Я пытаюсь пропинговать массив, содержащий разные хосты. В каждом цикле я сохраняю изображение в зависимости от того, был ли пинг успешным или нет (checkImg, errorImg). После этого я хочу представить информацию (имя хоста и img) в таблице.

Следующий код работает как-то, но он не стабилен. Иногда я получаю следующее предупреждение:

Тема 1: Неустранимая ошибка: индекс выходит за пределы диапазона. В строке: imgServer.image = UIImage (по имени: statusImagesMain [indexPath.row])

Так что я предполагаю, что цикл ping для разных хостов не был завершен до выполнения serverStatusTable.reloadData ().

Ты хоть представляешь, что я могу сделать, чтобы преодолеть эту проблему?

swift 4

import UIKit

class ServerVC: SimplePingDelegate, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var serverStatusTable: UITableView!

    let imageError = UIImage(named: "error")
    let imageCheck = UIImage(named: "check")

    var pings = ["www.apple.com", "www.appleidontknowwhy.de", "www.apple.com", "www.apple.com"]

    var hosts = [String]() // hostnames which get pinged
    var componentTextArray = [String]() // project names
    var statusImagesTemporary = [String]() // temporary store images
    var statusImagesMain = [String]() // array filled with temporary stored images
    var serverStatusMain = [String]() // server status string (connected, error)
    var serverStatusTemporary = [String]() // temporary server status

    override func viewDidLoad() {
        super.viewDidLoad()

        serverStatusTable.dataSource = self
        serverStatusTable.delegate = self

        statusImagesMain = ["error", "error", "error", "error"]
        componentTextArray = ["Project 1", "Project 2", "Project 3", "Project 4"]
        serverStatusMain = ["no data", "no data", "no data", "no data"]
        hosts = pings

        pingNext()
        serverStatusTable.reloadData()
        }

    override func viewDidAppear(_ animated: Bool) {
    // initial ping host process when loading the view
        startHostRequest()
    }

    @IBAction func refreshBtnAction(_ sender: Any) {
    // manual ping host process when clicking the button "refresh"
        startHostRequest()
    }


    func startHostRequest () {
        print("refresh server status")
        pingNext()
        // clear array before each host ping process in order for the array to keep only four items
        statusImagesMain.removeAll()
        serverStatusMain.removeAll()

        for statusImageTemporary in statusImagesTemporary {
            statusImagesMain.append(statusImageTemporary)
        }
        for i in serverStatusTemporary {
            serverStatusMain.append(i)
        }
        serverStatusTable.reloadData()
    }

    func pingNext() {
        guard pings.count > 0 else {
            return
        }
        let ping = pings.removeFirst()
        PlainPing.ping(ping, withTimeout: 1.0, completionBlock: { (timeElapsed:Double?, error:Error?) in
            if let latency = timeElapsed {
                print("\(ping) latency (ms): \(latency)")
                // fill temporary arrays with img and serverStatus text for successful connection
                self.statusImagesTemporary.append("check")
                self.serverStatusTemporary.append("Running ")
            }
            if let error = error {
                print("error: \(error.localizedDescription)")
                // fill temporary arrays with img and serverStatus text for failed connection attempt
                self.statusImagesTemporary.append("error")
                self.serverStatusTemporary.append("Error ")
            }
            self.pingNext()
        })
    }

// fill table with host data

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = serverStatusTable.dequeueReusableCell(withIdentifier: "serverStatusCell", for: indexPath)

        let lblServerStatus : UILabel = cell.contentView.viewWithTag(8) as! UILabel
        let imgServer : UIImageView = cell.contentView.viewWithTag(7) as! UIImageView


        imgServer.image = UIImage(named: statusImagesMain[indexPath.row])
        lblServerStatus.text = serverStatusMain[indexPath.row]

        return cell
    }
}

1 Ответ

0 голосов
/ 12 сентября 2018

Ваш баг лежит в startHostRequest() и tableView(_ tableView: UITableView, numberOfRowsInSection section: Int).

В startHostRequest() вы копируете statusImagesTemporary в statusImagesMain, и statusImageTemporary пусто в начале, и заканчивается .reloadData(). tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) возвращает componentTextArray.count, что всегда равно 4. Когда эти два значения объединяются один раз, когда вызывается startHostRequest(), таблица перезагружается с указанием иметь 4 строки, но для заполнения в строках имеется 0 строк данных.

Управление вашим UITableView можно упростить с помощью ALTableViewHelper [рекламный ролик - доступен на Framework Central здесь ]. Ячейки UITableView сохраняются для вас - в вашем случае они соответствуют содержанию statusImagesTemporary:

class ServerVC: UIViewController, UITableViewDelegate {

    @IBOutlet weak var serverStatusTable: UITableView!

    @objc let imageError = UIImage(named: "error")
    @objc let imageCheck = UIImage(named: "check")

    var pings = ["www.apple.com", "www.appleidontknowwhy.de", "www.apple.com", "www.apple.com"]

    var hosts = [String]() // hostnames which get pinged
    @objc var componentTextArray = [String]() // project names
    @objc var serverStatusMain = NSMutableArray() // not [String]() to allow changes to be observed

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // do not set dataSource, but instead:
        serverStatusTable.setHelperString(
            "section\n" +
            " body\n" +
            "  serverStatusCell * serverStatusMain\n" +
            "   $.viewWithTag:(8).text <~ @[1] == 'error' ? 'Error ' : 'Running '\n" +
            "   $.viewWithTag:(7).image <~ @[1] == 'error' ? imageError : imageCheck \n" +
            "   $.viewWithTag:(2).text <~ componentTextArray[@[0]]\n" +
            "", context:self)
        // @ is the value from the array (serverStatusMain), and $ is the serverStatusCell for @
        // The selector for UIView.viewWithTag() is 'viewWithTag:', which is why you see that in the helper string
        // Short arrays were added below as the values in serverStatusMain. In each short array:
        //   [0] is the index into hosts[] and componentTextArray[]
        //   [1] is the result of the ping, ie "check" or "error"
        //   so @[0] is the index and @[1] is the result of the ping

        serverStatusTable.delegate = self

        componentTextArray = ["Project 1", "Project 2", "Project 3", "Project 4"]
        hosts = pings
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    override func viewDidAppear(_ animated: Bool) {
        // initial ping host process when loading the view
        startHostRequest()
    }

    @IBAction func refreshBtnAction(_ sender: Any) {
        // manual ping host process when clicking the button "refresh"
        startHostRequest()
    }

    func startHostRequest () {
        // I thought you might need this here so that the 2nd and later ‘starts’ do the whole list
        pings = hosts

        // This will empty your UITableView
        serverStatusMain.removeAllObjects()

        print("refresh server status")
        pingNext()
    }

    func pingNext() {
        guard pings.count > 0 else {
            return
        }
        let ping = pings.removeFirst()
        PlainPing.ping(ping, withTimeout: 1.0, completionBlock:  { [weak self](timeElapsed:Double?, error:Error?) in
            if let me = self {
                if let latency = timeElapsed {
                    print("\(ping) latency (ms): \(latency)")
                    me.serverStatusMain.add([me.serverStatusMain.count, "check"])
                }
                if let error = error {
                    print("error: \(error.localizedDescription)")
                    me.serverStatusMain.add([me.serverStatusMain.count, "error"])
                }
                me.pingNext()
            }
        })
    }
}

Вы можете увидеть полный демонстрационный проект, включая этот код здесь .

...