Swift 我的主视图控制器是通过观察何时发布通知并多次调用来加载的

Swift 我的主视图控制器是通过观察何时发布通知并多次调用来加载的,swift,initialization,cllocationmanager,nsnotificationcenter,Swift,Initialization,Cllocationmanager,Nsnotificationcenter,我从一个显示gif的加载屏幕启动应用程序,同时在后台加载用户位置和相应的事件 我尝试在视图控制器上调用deinit()方法来删除观察者,并将视图控制器作为位置更新的委托删除,以确保位置更新和主屏幕的后续启动只调用一次 我的实现可能相当复杂,但我将努力确保它是清晰的。我从AppDelegate文件调用startApplication()以启动加载屏幕 AppDelegate func startApplication(animated: Bool, pushCategory: String?

我从一个显示gif的加载屏幕启动应用程序,同时在后台加载用户位置和相应的事件

我尝试在视图控制器上调用deinit()方法来删除观察者,并将视图控制器作为位置更新的委托删除,以确保位置更新和主屏幕的后续启动只调用一次

我的实现可能相当复杂,但我将努力确保它是清晰的。我从AppDelegate文件调用startApplication()以启动加载屏幕

AppDelegate



func startApplication(animated: Bool, pushCategory: String?) {

    let mainNC = self.window?.rootViewController as! UINavigationController
    let storyboard = UIStoryboard.init(name: "Main", bundle: nil)

    let homeVC = storyboard.instantiateViewController(withIdentifier: String(describing: LoadViewController.self)) as! LoadViewController
    if pushCategory != nil {
        homeVC.pushCategory = pushCategory!
    }
    mainNC.pushViewController(homeVC, animated: false)

}
在我的LoadVC中,我加载gif,然后添加一个观察者,用于观察何时从数据库检索到本地事件

   override func viewDidLoad() {
    super.viewDidLoad()

    holdView.frame = UIScreen.main.bounds
    holdView.loadGif(name: "ANO_loading_gif")
    holdView.contentMode = .scaleAspectFill

    showMessageView.layer.cornerRadius = 10.0
    showMessageView.clipsToBounds = true

    locationService.delegate = self

    if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {

        changeLocationMessage()
    }
}

 override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    //get notified when events have been downloaded from API
    NotificationCenter.default.addObserver(self, selector: #selector(receivedCloseEvents(_:)), name: NSNotification.Name(rawValue: Constants.Notifications.GET_EVENTS), object: nil)
}
找到位置后,将调用LocationService方法对服务器进行REST API调用

func tracingLocation(当前位置:CLLocation){

然后,在我的“GlobalService”文件中,如果调用成功,则会在后台运行一系列函数,因为它们非常耗时

  func updateUserLocation(_ UserLocation: CLLocation) {

    g_userCLLocation = UserLocation
    g_userCurrentLocation = nil

    // get user location to update Hub name
    for location in g_aryLocations {
        let coreLocation = CLLocation(latitude: location.location_latitude!, longitude: location.location_longitude!)
        let fDistance = coreLocation.distance(from: UserLocation)

        // check event distance
        if fDistance < Double(Constants.Numbers.EVENT_LIST_DISTANCE) {
            g_userCurrentLocation = location
            break
        }
    }

    if g_userCLLocation != nil {

        // get all valid events
        WebService.sharedInstance().getActiveEvents(UserLatitude: UserLocation.coordinate.latitude, UserLongitude: UserLocation.coordinate.longitude)
        { (aryEvents, error) in
            if let error = error {
                //show issue with network & load from archives if accessible
            } else {

             //set events to the empty array
             //move these time expensive tasks to background thread
                self.group.enter()

                //execute event recovery on background thread
                DispatchQueue.global(qos: .background).async {
                    self.g_aryEvents = aryEvents!
                    self.getUsersWithinRange(aryEvents!)
                    self.updateUserEvent(nil)
                }

            }
        }

    }

}
然后我调用deinit()方法来删除观察者,并取消分配LoadVC作为LocationService委托

 deinit {
    //remove location service delegate
    locationService.delegate = nil
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: Constants.Notifications.GET_EVENTS), object: nil)
}
通常情况下,它的行为符合预期,但有时它会多次推送MainVC。我还将g_usercllocation的属性观察器放置在didSet中,并将“location called”打印两次。我不确定是否如此,因为我使用的是requestLocation()对于位置,我认为在找到位置时只能调用一次。

两个可能的问题:

1-对通知进行多次观察

2-发布一次以上的通知

由于您需要对
receivedCloseEvents
方法进行一次分派,因此请在
receivedCloseEvents
方法的最开始处放置以下行

NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: Constants.Notifications.GET_EVENTS), object: nil)

因此,一旦收到通知,它就会被取消注册,直到视图再次出现并重新注册事件。

然而,当视图即将消失或新视图已加载时(即在viewDidLoad()方法中),移除观察者不是最佳做法吗这完全取决于您的需要。最重要的事情通常是观察操作和不观察操作应该使用逻辑相反的方法。
init
->
deinit
或例如
出现
->
消失
等。但是在这种情况下,您提到只需要执行一次函数。因此您应该取消方法执行后立即注册。@onicha21我知道,只是在
GlobalService
中,当我观察属性
g_UserCLLocation
时,它设置了两次。这让我觉得它与
CLLocationManager
有关,因为变量在
updateUserLocation()中只设置了一次
method是的,我可以通过将通知移动到选择器功能来解决此问题,谢谢!
   @objc func receivedCloseEvents(_ notification:Notification) {

    locationService.stopUpdatingLocation()

    let g_events = GlobalService.sharedInstance().g_aryEvents

    self.events = g_events
    //send events to Main VC once done

        let mainVC = self.storyboard?.instantiateViewController(withIdentifier: String(describing: MainViewController.self)) as! MainViewController
        mainVC.arrEvents = self.events

        if self.pushCategory != nil {
            mainVC.pushCategory = self.pushCategory!
        }

        self.navigationController?.pushViewController(mainVC, animated: true)
    }
 deinit {
    //remove location service delegate
    locationService.delegate = nil
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: Constants.Notifications.GET_EVENTS), object: nil)
}
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: Constants.Notifications.GET_EVENTS), object: nil)