Ios 更改NSFetchedResultsController NSPreditate后不断调用NSMangeObject子类方法
我一直被困在这里,找不到罪犯。我将尽可能多地包含有用的代码。TL见底部;博士版本 创意Ios 更改NSFetchedResultsController NSPreditate后不断调用NSMangeObject子类方法,ios,core-data,swift2,Ios,Core Data,Swift2,我一直被困在这里,找不到罪犯。我将尽可能多地包含有用的代码。TL见底部;博士版本 创意 用户打开应用程序后,您可以在某个城市中查找餐馆,或将其设置为查找您所在位置附近的餐馆(假设您允许应用程序查看您的位置)。如果设置城市,则NSFetchedResultsController将使用特定的NSPredicate执行提取。当您点击按钮查找附近的餐厅时,它会更改NSPredicate,并再次执行提取 设置 1) 加载myUIViewController时,它调用了NSUserDefaults子类上的方
用户打开应用程序后,您可以在某个城市中查找餐馆,或将其设置为查找您所在位置附近的餐馆(假设您允许应用程序查看您的位置)。如果设置城市,则NSFetchedResultsController将使用特定的
NSPredicate
执行提取。当您点击按钮查找附近的餐厅时,它会更改NSPredicate
,并再次执行提取
设置1) 加载my
UIViewController
时,它调用了NSUserDefaults
子类上的方法来获取用户的当前位置。2) 此方法告诉
CLLocationManager
对象开始更新用户的位置,一旦更新了位置,就会调用didUpdateLocations
方法。3) 由于我已将
.desiredAccuracy
设置为kCallocationAccuracyBest
因此经常调用didUpdateLocations
方法,因此,我设置了一个计时器来执行一个名为updateRestaurantInstance
的方法,该方法在主NSManagedObjectContext
上执行一次提取,并检索数据库中的所有餐厅。4) 循环遍历每个餐厅并调用一个方法来设置餐厅与用户的距离。
5) 循环完成后,我用更新的值保存上下文 问题
当我启动应用程序时,一切都正常运行,一旦从
4)
提取完成对每个项目的迭代,我就可以点击按钮获取我附近的餐厅。但是,如果
4)
中的迭代没有完成,我点击找到我附近餐馆的按钮,迭代就完成了,但是上下文没有保存(我已经设置了print
语句),更新餐馆距离的方法被称为无限阻塞主线程并使UI不可用
代码-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()
}
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
}
如果需要,很高兴添加更多,谢谢
EDIT:似乎它在updateRestaturantInstance()
中进入try context.save()
,并在那里启动循环(即它没有进入print
语句)
太长了,读不下去了!>编辑> 2 <强>:TL;DR代码版本:这会更新餐厅与用户的距离,
try
s位于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
工作或者
- 禁用导致重新加载的UI控件,直到完成所有操作
- 保留一个Bool变量,指示是否在各个位置循环。点击控件时,更改此变量。在循环中检查变量,如果变量已更改,则中止,并从头开始而不保存
- 哦,天哪。
哇
让我们回忆一下getter和setter,在大多数与swift不同的编程语言中,比如Java,您必须使用方法来创建它们
private var distance = 1
getDistance() -> Int {
return self.distance
}
但是在swift中,这是不必要的。无论如何,我的
getDistance
方法被调用用于我的NSPredicate
。我将该方法的名称更改为getRestaurantInstance
,并且一切都按预期运行。不要像我的和name方法那样,也被命名为getter和setter。知道是什么吗发生在后台?我很好奇为什么会发生这种情况。目前,我会按照你说的做,快速点击UIActivityIndicatorView
,禁用该按钮。你发布了太多的代码,无法对此进行分析。如果你将其减少到描述问题的必要行数,我会看一看。谢谢,我更新了m用最少的代码回答y问题-请参阅问题的底部。
predicate = NSPredicate(format: "city LIKE %@", "New York")
fetchController.fetchRequest.predicate = predicate
try fetchController.performFetch
private var distance = 1
getDistance() -> Int {
return self.distance
}