我一直坚持这个,找不到罪魁祸首。我将尝试尽可能多地包含有用的代码。请参阅TL; DR版本的底部。
IDEA
用户打开应用程序,您可以找到某个城市的餐馆或将其设置为查找您所在位置附近的餐馆(假设您允许该应用查看您的位置)。如果设置了城市,则NSFetchedResultsController将使用某个NSPredicate
执行提取。当您点击按钮查找您附近的餐馆时,它会更改NSPredicate
并再次执行获取。
设置
1)当我的UIViewController
被加载时,它在NSUserDefaults
的子类上调用了一个方法来获取用户的当前位置。
2)此方法告诉CLLocationManager
对象开始更新用户的位置,一旦更新了位置,就会调用didUpdateLocations
方法。
3)由于.desiredAccuracy
设置为kCLLocationAccuracyBest
,didUpdateLocations
方法经常被调用,所以我设置了一个定时器来执行一个名为updateRestaurantDistance
的方法,该方法对主进行提取NSManagedObjectContext
并检索数据库中的所有餐馆
4)循环遍历每个餐馆并调用一种方法来设置餐馆与用户的距离
5)循环完成后,我使用更新的值保存上下文。
问题
当我启动应用程序时,一切运行正常,一旦从4)
获取完成迭代完每个项目,我就可以点击获取我附近餐馆的按钮。
但是,如果4)
的迭代没有完成,我点击找到我附近餐馆的按钮,迭代完成,但上下文没有保存(我设置了print
个语句更新餐厅距离的方法称为无限阻塞主线程并使UI无法使用。
CODE
- UIViewController
override func viewDidLoad() {
super.viewDidLoad()
//configure properties
//core data
context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
//fetch controller
fetchController.delegate = self
//default values
user = User()
self.user.getCurrentLocation()
}
//method that is called when the button to filter restaurants near user is tapped
func nearMe() {
restaurantPredicate = NSPredicate(format: "(distance < %f AND distance > %f) AND SUBQUERY(specials,$s, ($s.type LIKE %@ OR $s.type LIKE %@) AND $s.day LIKE %@).@count > 0",
user.doubleForKey(UserData.MaxDistance.rawValue), 0.01, typeQuery!, "Combo", day)
fetchController.fetchRequest.sortDescriptors = [distSort,nameSort,citySort]
do {
try fetchController.performFetch()
} catch {
print("Error fetching when sorting by near me")
}
tableView.reloadData()
}
具有获取位置的方法的User
类
func getCurrentLocation() {
//ask for access to location (if not given)
if CLLocationManager.locationServicesEnabled() {
locationManager.requestWhenInUseAuthorization()
}
//if allowed, start checking for location
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
CLLocationDelegate
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// get coordintes
if let locValue: CLLocationCoordinate2D = manager.location?.coordinate {
//check if timer has started
if timer == nil {
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateRestaurantDistance", userInfo: nil, repeats: false)
} else {
timer?.invalidate()
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateRestaurantDistance", userInfo: nil, repeats: false)
}
//stop updating since we're done
locationManager.stopUpdatingLocation()
}
}
更新位置方法
func updateRestaurantDistance() {
let fetch = NSFetchRequest(entityName: "Restaurant")
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
do {
let results = try context.executeFetchRequest(fetch) as! [Restaurant]
for result in results {
print(results.indexOf(result))
result.getDistance()
}
} catch {
print("Error updating restaurant distances from UserClass")
}
do {
try context.save()
print("saved context")
} catch {
print("error saving context while updating restaurant distance: \(error)")
}
}
餐厅方法
//This method gets called infinitely and I have no idea why
func getDistance() {
print("getDistance")
guard CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse else {
return
}
self.distance = self.getDistanceFromRestaurant()
}
func getDistanceFromRestaurant() -> CLLocationDistance {
let user = User()
guard CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse else {
return Double(0)
}
let longitude = user.doubleForKey(UserData.Longitute.rawValue)
let latitude = user.doubleForKey(UserData.Latitude.rawValue)
guard abs(longitude) + abs(latitude) > 0 else {
return Double(0)
}
let loc = CLLocation(latitude: latitude, longitude: longitude)
let selfLoc = CLLocation(latitude: Double(self.latitude), longitude: Double(self.longitude))
return loc.distanceFromLocation(selfLoc) / 1000
}
如果需要可以添加更多,谢谢!
编辑:似乎它到达try context.save()
中的updateRestaurantDistance()
并在那里开始循环(也就是说它没有到达print
语句
编辑2 :TL; DR代码版本:
这会更新餐馆与用户的距离,try
位于do-catch区块中,但为了简单起见已删除
func updateRestaurantDistance() {
let fetch = NSFetchRequest(entityName: "Restaurant")
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let results = try context.executeFetchRequest(fetch) as! [Restaurant]
for result in results {
result.getDistance()
}
try context.save()
}
func getDistance() {
self.distance = 10 // method to calculate distance is called, but for simplicity set to 10
}
当updateResturantDistance
正在运行时,我无法将NSPredicate
更改为具有distance
属性的任何内容,并对我的NSFetchedResultsController
执行提取,即:
predicate = NSPredicate(format: "distance < %f", 10)
fetchController.fetchRequest.predicate = predicate
try fetchController.performFetch
不起作用,但
predicate = NSPredicate(format: "city LIKE %@", "New York")
fetchController.fetchRequest.predicate = predicate
try fetchController.performFetch
作品
答案 0 :(得分:0)
无论
或
答案 1 :(得分:0)
OH。 MY。善良。
WOW
让我们回忆一下吸气鬼和二传手。在大多数编程语言中,不像swift即Java,你必须用方法创建它们,即
private var distance = 1
getDistance() -> Int {
return self.distance
}
但在迅速,这是没有必要的。无论如何,我的getDistance
调用了NSPredicate
方法。我将方法的名称更改为getRestaurantDistance
,一切都按预期运行。不要像我的名字方法那样命名为getter和setter。