我正在努力让我的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对象都加载了数据。
答案 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