Ios 更改NSFetchedResultsController NSPreditate后不断调用NSMangeObject子类方法

Ios 更改NSFetchedResultsController NSPreditate后不断调用NSMangeObject子类方法,ios,core-data,swift2,Ios,Core Data,Swift2,我一直被困在这里,找不到罪犯。我将尽可能多地包含有用的代码。TL见底部;博士版本 创意 用户打开应用程序后,您可以在某个城市中查找餐馆,或将其设置为查找您所在位置附近的餐馆(假设您允许应用程序查看您的位置)。如果设置城市,则NSFetchedResultsController将使用特定的NSPredicate执行提取。当您点击按钮查找附近的餐厅时,它会更改NSPredicate,并再次执行提取 设置 1) 加载myUIViewController时,它调用了NSUserDefaults子类上的方

我一直被困在这里,找不到罪犯。我将尽可能多地包含有用的代码。TL见底部;博士版本

创意
用户打开应用程序后,您可以在某个城市中查找餐馆,或将其设置为查找您所在位置附近的餐馆(假设您允许应用程序查看您的位置)。如果设置城市,则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
      }