等待数据加载到模型中,然后在 ViewController 中访问它们
Wait for data to get loaded in model before accessing them in ViewController
我正在努力让我的 ViewVontroller 知道何时成功加载了所有数据。我的 ViewController 有一个 Stop 对象列表,所有这些对象都有一个 Bus 对象列表。在每个 Stop 中,我调用一个 API 并填充 Bus 对象列表。我在每个 Stop 对象中都得到了完成块,用于了解作业何时完成。但是,当我想在 ViewController 中使用它们时,我几乎不知道该怎么做。在我使用它们之前,我想确保每个 Stop 对象都有一个完整的总线列表。目前的解决方案是等待 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 对象都加载了数据。
添加所有元素时发出通知,例如:
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)
}
在处理异步请求时对时间做出假设是个坏主意,是的,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)
})
}
当你分配 LoadingViewController
的 nearbyStops
变量时,你可以将控制器分配为每个 stop
对象的委托并实现委托,你还需要一个计数器已完成加载的站点:
var stopDeparturesFetchedCount = 0
func stopDidFetchDepartures(stop: Stop) {
stopDeparturesFetchedCount += 1
if stopDeparturesFetchedCount >= nearbyStops.count {
print("All stops finished loading")
}
}
确实不应该违反 MVC,而使用 same.You 应该采用 MVVM 模式而不是 MVC。
以下是详尽的教程,可将其合并到您的 ios 应用程序中。
https://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1
我正在努力让我的 ViewVontroller 知道何时成功加载了所有数据。我的 ViewController 有一个 Stop 对象列表,所有这些对象都有一个 Bus 对象列表。在每个 Stop 中,我调用一个 API 并填充 Bus 对象列表。我在每个 Stop 对象中都得到了完成块,用于了解作业何时完成。但是,当我想在 ViewController 中使用它们时,我几乎不知道该怎么做。在我使用它们之前,我想确保每个 Stop 对象都有一个完整的总线列表。目前的解决方案是等待 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 对象都加载了数据。
添加所有元素时发出通知,例如:
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)
}
在处理异步请求时对时间做出假设是个坏主意,是的,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)
})
}
当你分配 LoadingViewController
的 nearbyStops
变量时,你可以将控制器分配为每个 stop
对象的委托并实现委托,你还需要一个计数器已完成加载的站点:
var stopDeparturesFetchedCount = 0
func stopDidFetchDepartures(stop: Stop) {
stopDeparturesFetchedCount += 1
if stopDeparturesFetchedCount >= nearbyStops.count {
print("All stops finished loading")
}
}
确实不应该违反 MVC,而使用 same.You 应该采用 MVVM 模式而不是 MVC。 以下是详尽的教程,可将其合并到您的 ios 应用程序中。 https://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1