等待数据加载到模型中,然后在ViewController中访问它们

时间:2016-06-19 15:47:23

标签: ios json swift viewcontroller

我正在努力让我的ViewVontroller知道所有数据何时成功加载。我的ViewController有一个Stop对象列表,所有这些对象都有一个Bus对象列表。在每个Stop中,我调用一个API并填充Bus对象列表。我在每个Stop对象中都知道完成作业的完成块。但是,当我想在我的ViewController中使用它时,我几乎失去了怎么做。在使用它们之前,我想确保每个Stop对象都有一个完整的Busses列表。目前的解决方案是等待2秒然后使用它们,这不是一个更好的解决方案,但它给了我一些数据可以使用。有什么建议?我想我不能在我的模型中从我的ViewController调用一个方法,因为这会破坏MVC模式,对吧?

class LoadingViewController: UIViewController {

var nearbyStops = [Stop]()

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

    GPSUtil.sharedInstance.startGPS()

    stopsNearby(initialLocation, maxRadius: 1000, maxNumber: 5)

}

// MARK: - API work

/**
 Assigns the array of Stops to the nearby stops
*/
func stopsNearby(location: CLLocationCoordinate2D, maxRadius: Int, maxNumber: Int) {
    APIHelper.sharedInstance.getStopsNearby(location, maxRadius: maxRadius, maxNumber: maxNumber) { (result) -> Void in
        self.nearbyStops = result!
        self.test()
    }
}

func test() {
    let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 2 * Int64(NSEC_PER_SEC))
    dispatch_after(time, dispatch_get_main_queue()) {
        }
        for item in self.nearbyStops {
            let items = item.getDepartures()
            print(item.name!)
            for element in items {
                element.timeUtilDeparture()
                print("    " + element.name + " - " + element.direction)
                print("          \(element.times)")
                print(element.timeUntilDepartureList)
            }
        }
    }
}

class Stop: NSObject, MKAnnotation {

var departures = [Departure]()
var busses = [Bus]()

init(name: String, coordinate: CLLocationCoordinate2D, stopID: Int64, distance: Int) {
    self.name = name
    self.coordinate = coordinate
    self.stopID = stopID
    self.distance = distance
    super.init()
    loadDepartures() { (result) -> Void in
        self.sanitizeBusDepartures( { (result) -> Void in
            // THE CURRENT OBJECT IS LOADED WITH DATA
        })
    }
}

/**
    Loads the departures for the current stop.
*/
private func loadDepartures(completion: ((result: Bool) -> Void)!) {
    let date = NSDate()
    let calender = NSCalendar.currentCalendar()
    let components = calender.components([.Hour, .Minute, .Day, .Month, .Year], fromDate: date)
    let currentHour = components.hour
    let currentMinute = components.minute
    let currentDay = components.day
    let currentMonth = components.month
    let currentYear = components.year

    let currentDate = "\(currentDay).\(currentMonth).\(currentYear)"
    let currentTime = "\(currentHour):\(currentMinute)"

    let specificURL = "URL"

    let url: NSURL = NSURL(string: specificURL)!
    let session = NSURLSession.sharedSession()

    let task = session.dataTaskWithURL(url)
    { (data, resonse, error) -> Void in
        if error == nil {

            let dataReturned = JSON(data: data!)

            let departures = dataReturned["DepartureBoard"]["Departure"]
            for (_, value):(String, JSON) in departures {
                let busName = value["name"].stringValue
                let stop = value["stop"].stringValue
                let time = value["time"].stringValue
                let delay = value["messages"].intValue
                let date = value["date"].stringValue
                let finalStop = value["finalStop"].stringValue
                let direction = value["direction"].stringValue
                let journeyDetailUrl = value["JourneyDetailRef"]["ref"].stringValue

                self.departures.append(
                    Departure(name: busName,
                        stop: stop,
                        time: time,
                        delay: delay,
                        date: date,
                        finalStop: finalStop,
                        direction: direction,
                        journeyDetailLink: journeyDetailUrl))
            }
        }

        completion(result: true)
    }

    task.resume()
}

private func sanitizeBusDepartures(completion: ((result: Bool) -> Void)!) {
        var tempList = [Bus]()

        for item in departures {
            tempList.append(Bus(name: item.name!, direction: item.direction!, times: item.time!))
        }

        for item in tempList {
            if busses.contains(item) {
                let indexOfElement = busses.indexOf(item)
                busses[indexOfElement!].times += item.times
            } else {
                busses.append(item)
            }

        }

        completion(result: true)
    }

正如您在上面所看到的,每个Bus对象都从它自己的URL加载它自己的数据,所以在我的ViewController中我想确保每个Stop对象都加载了数据。

3 个答案:

答案 0 :(得分:0)

在添加所有元素时触发通知,如:

self.departures.append(
                    Departure(name: busName,
                        stop: stop,
                        time: time,
                        delay: delay,
                        date: date,
                        finalStop: finalStop,
                        direction: direction,
                        journeyDetailLink: journeyDetailUrl))
            }
        }

        completion(result: true)
    NSNotificationCenter.defaultCenter().postNotificationName("Completed", object: nil)
    }

    task.resume()
}

private func sanitizeBusDepartures(completion: ((result: Bool) -> Void)!) {
        var tempList = [Bus]()

        for item in departures {
            tempList.append(Bus(name: item.name!, direction: item.direction!, times: item.time!))
        }

        for item in tempList {
            if busses.contains(item) {
                let indexOfElement = busses.indexOf(item)
                busses[indexOfElement!].times += item.times
            } else {
                busses.append(item)
            }

        }

        completion(result: true)

    }

然后在test()

中收到它
func test(notification: NSNotification){
 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.test(_:)), name: "Completed", object: nil)
//Your code..
}

然后删除观察者:

deinit{
NSNotificationCenter.defaultCenter().removeObserver(self)
}

答案 1 :(得分:0)

在处理异步请求时做出关于时间的假设是一个坏主意,是的,dispatch_groups会起作用,但我提出了一个更简单的解决方案,委托,创建协议StopDelegate或某个名称,对你有意义,每个Stop对象都可以有一个stopDelegate变量:

protocol StopDelegate: class {
   func stopDidFetchDepartures(stop: Stop)
}

class Stop: NSObject, MKAnnotation {
   weak var stopDelegate: StopDelegate?
   ...
}

当出发和公共汽车信息准备就绪时,Stop对象通知其代表:

loadDepartures() { (result) -> Void in
    self.sanitizeBusDepartures( { (result) -> Void in
        // THE CURRENT OBJECT IS LOADED WITH DATA
        self.stopDelegate. stopDidFetchDepartures(self)
    })
}

当您分配nearbyStops的{​​{1}}变量时,您可以将控制器指定为每个LoadingViewController对象的委托并实现委托,您还需要一个计数器来停止已经完成加载:

stop

答案 2 :(得分:0)

确实你不应该在使用它时违反MVC。你应该采用MVVM模式而不是MVC。 以下是在您的ios应用程序中包含相同内容的详尽教程。 https://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1