CLLLocationManager и доставка обновлений местоположения в разные части приложения.

В моем приложении у меня есть фоновая служба и контроллер представления, которому требуется обновление местоположения (не постоянно). Итак, я подумал, что лучше иметь одноэлементный класс для сбора обновлений местоположения и распространения их в разные части моего приложения, а не делегировать каждому объекту, которому требуется местоположение.

Мой менеджер местоположения - это одноэлементный класс, который устанавливает CLLocationManager, включает местоположение, когда что-то вызывает диспетчер местоположения и запрашивает местоположение. Как это работает, у него есть метод currentLocation, который принимает закрытие в качестве аргумента. LocationManager сохраняет закрытия, переданные этому методу, в массиве. Каждый раз, когда вызывается метод, locationManager включает обновления местоположения, и, когда у него достаточно хорошее местоположение, он выполняет все закрытия, передавая им полученное местоположение и очищая ExecutionQueue.

Я знаю о циклах сохранения и осторожен со списками захвата, приведенными в замыканиях. Однако я получаю редкий thunk for @escaping @callee_guaranteed crash, пока выполняется закрытие. В последний раз, когда я получил это, логи жаловались на плохое использование weak. Я использую объект со слабой ссылкой (weak self) в закрытии, но остальная часть закрытия выполняется только в том случае, если слабая ссылка действительно содержит ссылку на объект (if let self = self { ... })

У меня есть несколько вопросов

  1. Это плохой дизайн? Могу я сделать это лучше?

  2. Я знаю, что NSNotifications также являются эффективным способом отправки данных в разные части приложения. Я хочу знать, лучше это или хуже моего дизайна и как.

  3. Когда я хочу отправлять непрерывные обновления местоположения различным объектам, какой метод является хорошим? Например, добавление наблюдателя с целью и селектором (это objectiveC-ish)

  4. Я имею в виду другой дизайн. В моем locationManager будет метод addObserver с аргументом, который является объектом, реализующим протокол для получения обновлений местоположения. Это хороший дизайн?


person Brucschothaman Waynekattaraman    schedule 08.07.2020    source источник
comment
Я бы рекомендовал использовать Combine Publisher.   -  person Alexander    schedule 08.07.2020
comment
Publisher - интересный дизайн, и я об этом не подозревал. Спасибо. Я, вероятно, смогу использовать его в своих будущих проектах, но для этого нужна совместимость с iOS 12 и 11.   -  person Brucschothaman Waynekattaraman    schedule 08.07.2020
comment
Вы можете использовать OpenCombine для старых платформ, это реализация Combine API с открытым исходным кодом. И, конечно же, есть RxSwift, который существует уже много лет.   -  person Alexander    schedule 08.07.2020


Ответы (1)


Есть решение, похожее на уведомления, но я думаю, что оно лучше, потому что у вас может быть много сообщений, и их легче поддерживать в чистоте. Если целью является ios 13+, вы определенно можете использовать Publisher.

Создайте протокол для своего синглтона

protocol YourLocationManagerDelegate: class {
    func didUpadteUserPosition()
}

Класс: позволяет использовать объект делегата как слабую ссылку.

в вашем синглтон-менеджере создайте список делегатов

private var delegates: [YourLocationManagerDelegate?] = []

в вашем синглтон-менеджере создайте метод регистрации и отмены регистрации

func register(Delegate delegate: YourLocationManagerDelegate) {
    if delegates.contains(where: { (delegateToCheck) -> Bool in
        return delegateToCheck === delegate
    }) == false {
        self.delegates.append(delegate)
    }
}

func unregister(Delegate delegate: YourLocationManagerDelegate) {
    self.delegates.removeAll { (delegateToCheck) -> Bool in
        return delegateToCheck === delegate
    }
}

в своем объекте зарегистрируйтесь со слабым я

weak var this = self
UserLocationManager.shared.register(Delegate: this)

в вашем менеджере, когда вы получаете новое обновление, прокрутите делегатов и вызовите update.

func locationUpdated() {
    for delegate in delegates {
        delegate?.didUpadteUserPosition()
    }
}

поскольку объект регистрируется как слабая ссылка, он не сохраняется при деинициализации. Кроме того, вы можете отменить регистрацию в деинициализации этих объектов, но это не обязательно.

person Tomo Norbert    schedule 08.07.2020