NSTimer() 运行 可以不停吗? (Xcode v 7.0.1,Swift 2.0)

Can NSTimer() run non-stop? (Xcode v 7.0.1, Swift 2.0)

我正在构建一个 iOS 应用程序,它使用 Google Maps SDK 在地图上显示我学校的校园班车位置。我通过解析每 10 秒刷新一次的 XML 文件来获取航天飞机的位置。

我每 10 秒使用一次 NSTimer() 到 运行 viewDidLoad(),以便在地图上更新公交车的位置。

我遇到的问题是,在 viewDidLoad() 的 6 或 7 运行 秒后,代码崩溃了。这很糟糕,因为我需要不断刷新我的代码才能更新公交车的位置。

我是否正确使用了 NSTimer()? NSTimer() 可以连续保持 运行ning 或者 NSTime() 可以持续多长时间 运行?

以下是我的代码:

import UIKit
import GoogleMaps

class ViewController: UIViewController, NSXMLParserDelegate {

    var parser = NSXMLParser()
    var timer  = NSTimer()

    // viewDidLoad()
    override func viewDidLoad() {
        super.viewDidLoad()

        // runs viewDidLoad() every 10 seconds
        timer = NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: "viewDidLoad", userInfo: nil, repeats: true)

        // XML file
        parser = NSXMLParser(contentsOfURL:(NSURL(string:"http://link.to.xml.file.xml"))!)!

        let coord = Coord2()
        parser.delegate = coord
        parser.parse()
        print("coord has a count attribute of \(coord.count)")
        print("coord has \(coord.markers.count) markers")

        // displays the map adjusted to UC Santa Cruz
        let camera = GMSCameraPosition.cameraWithLatitude(37.0000,
        longitude: -122.0600, zoom: 14)
        let mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
        mapView.mapType = kGMSTypeNormal
        mapView.myLocationEnabled = true
        self.view = mapView

        // loops through all the lats and lngs of the buses and produces a marker
        // for them on our Google Maps app
        for marker in coord.markers {
            print("marker id=\(marker.id), lat=\(marker.lati), lng=\(marker.lngi), route=\(marker.route)")

            // displays the buses
            let buses = GMSMarker()
            buses.position = CLLocationCoordinate2DMake(marker.lati, marker.lngi)
            buses.title = marker.route
            if buses.title == "UPPER CAMPUS" {
                buses.icon = UIImage(named: "uppercampus")
            } else if buses.title == "LOOP" {
                buses.icon = UIImage(named: "innerloop")
            }
            buses.snippet = marker.id
            buses.map = mapView
        }
    }

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

// ParseBase class
// simple base class that is used to consume foundCharacters
// via the parser
class ParserBase : NSObject, NSXMLParserDelegate  {

    var currentElement:String = ""
    var foundCharacters = ""
    weak var parent:ParserBase? = nil

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        currentElement = elementName
    }

    func parser(parser: NSXMLParser, foundCharacters string: String) {
        self.foundCharacters = string
    }

}

// Coord2 class
// represents a coord2 tag
// it has a count attribute
// and a collection of markers
class Coord2 : ParserBase {

    var count = 0
    var markers = [Marker]()

    // didStartElement()
    override func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {

        print("processing <\(elementName)> tag from Coord")

        if elementName == "coord2" {

            // if we are processing a coord2 tag, we are at the root
            // of XML file, extract the count value and set it
            print(attributeDict["count"])
            if let c = Int(attributeDict["count"]!) {
                self.count = c
            }
        }

        // if we found a marker tag, delegate further responsibility
        // to parsing to a new instance of Marker
        if elementName == "marker" {
            let marker = Marker()
            self.markers.append(marker)

            // push responsibility
            parser.delegate = marker

            // let marker know who we are
            // so that once marker is done XML processing
            // it can return parsing responsibility back
            marker.parent = self
        }
    }
}

// Marker class
class Marker : ParserBase {

    var id = ""
    var lat = ""
    var lng = ""
    var route = ""
    var lati = 0.0
    var lngi = 0.0

    // didEndElement()
    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {

        print("processing <\(elementName)> tag from Marker")

        // if we finished an item tag, the ParserBase parent
        // would have accumulated the found characters
        // so just assign that to our item variable
        if elementName == "id" {
            self.id = foundCharacters
        }

        // convert the lat to a Double
        else if elementName == "lat" {
            self.lat = foundCharacters
            // cast self.lat as Double
            if let doubleFromlat = Double(self.lat) {
                self.lati = doubleFromlat
            } else { print("foundCharacters for lat does not hold double") }

        }

        // convert the lng to a Double
        else if elementName == "lng" {
            self.lng = foundCharacters
            if let doubleFromlng = Double(self.lng) {
                self.lngi = doubleFromlng
            } else { print("foundCharacters for lng does not hold double") }
        }

        else if elementName == "route" {
            self.route = foundCharacters
        }

        // if we reached the </marker> tag, we do not
        // have anything further to do, so delegate
        // parsing responsibility to parent
        else if elementName == "marker" {
            parser.delegate = self.parent
        }

        // reset found characters
        foundCharacters = ""
    }

}

每次都调用 viewDidLoad 方法是个坏主意。

viewDidLoad is called exactly once, when the view controller is first loaded into memory. This is where you want to instantiate any instance variables and build any views that live for the entire lifecycle of this view controller. However, the view is usually not yet visible at this point.

不是每次都调用 viewDidLoad 方法,而是创建另一个方法并将所需的代码添加到您想要每 10 秒 运行 的方法中,如下所示:

timer = NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: "yourNewMethod", userInfo: nil, repeats: true)

如上所示更新您的timer

下面是辅助方法。

func yourNewMethod() {
    //add your code here which you want to run
}