CLLLLocationManager และส่งมอบการอัปเดตตำแหน่งไปยังส่วนต่างๆ ของแอป

ในแอปของฉัน ฉันมีบริการพื้นหลังและตัวควบคุมมุมมองที่ต้องการการอัปเดตตำแหน่ง (ไม่ตลอดเวลา) ดังนั้น ฉันคิดว่าจะดีกว่าถ้ามีคลาสเดี่ยวเพื่อบันทึกการอัปเดตตำแหน่งและแจกจ่ายไปยังส่วนต่างๆ ของแอปของฉัน แทนที่จะมอบหมายในทุกออบเจ็กต์ที่ต้องการตำแหน่ง

ผู้จัดการสถานที่ของฉันเป็นคลาสเดี่ยวที่ตั้งค่า CLLocationManager เปิดตำแหน่งเมื่อมีบางสิ่งโทรหาผู้จัดการสถานที่และขอตำแหน่ง วิธีการทำงานนี้มีเมธอด currentLocation ที่ยอมรับการปิดเป็นอาร์กิวเมนต์ locationManager จัดเก็บการปิดที่ส่งผ่านไปยังวิธีนี้ในอาร์เรย์ เมื่อใดก็ตามที่มีการเรียกใช้เมธอด locationManager จะเปิดการอัปเดตตำแหน่ง และเมื่อมีตำแหน่งที่ดีเพียงพอแล้ว ก็จะดำเนินการปิดทั้งหมด โดยส่งตำแหน่งที่ได้มาเข้าไปและล้างคิวการดำเนินการ

ฉันทราบถึงรอบการเก็บรักษา และฉันระมัดระวังกับรายการจับที่ให้ไว้ในการปิด อย่างไรก็ตาม ฉันได้รับ thunk for @escaping @callee_guaranteed crash ที่หายากในขณะที่กำลังดำเนินการปิด ครั้งสุดท้ายที่ฉันได้รับสิ่งนี้ บันทึกบ่นเกี่ยวกับการใช้งานที่อ่อนแอของความอ่อนแอ ฉันกำลังใช้วัตถุอ้างอิงที่อ่อนแอ (ตัวเองที่อ่อนแอ) ในการปิด แต่การปิดส่วนที่เหลือจะดำเนินการก็ต่อเมื่อการอ้างอิงที่อ่อนแอนั้นมีการอ้างอิงถึงวัตถุจริง ๆ (if let self = self { ... })

ฉันมีคำถามสองสามข้อ

  1. นี่เป็นการออกแบบที่ไม่ดีเหรอ? ฉันสามารถทำได้ด้วยวิธีที่ดีกว่านี้หรือไม่?

  2. ฉันรู้ว่า NSNotifications ยังเป็นวิธีที่ใช้ได้ผลในการส่งข้อมูลไปยังส่วนต่างๆ ของแอป ฉันอยากรู้ว่าสิ่งนี้ดีกว่าหรือแย่กว่าการออกแบบของฉันและอย่างไร

  3. เมื่อฉันต้องการส่งการอัปเดตตำแหน่งอย่างต่อเนื่องไปยังออบเจ็กต์ต่างๆ วิธีใดคือวิธีที่ดี เช่นการเพิ่มผู้สังเกตการณ์ด้วยเป้าหมายและตัวเลือก (นี่คือ objectC-ish)

  4. ฉันมีการออกแบบอื่นในใจ locationManager ของฉันจะมีเมธอด addObserver พร้อมอาร์กิวเมนต์ที่เป็นออบเจ็กต์ที่ใช้โปรโตคอลเพื่อรับการอัปเดตตำแหน่ง นี่เป็นการออกแบบที่ดีหรือไม่?


person Brucschothaman Waynekattaraman    schedule 08.07.2020    source แหล่งที่มา
comment
ฉันอยากจะแนะนำให้ใช้ Combine Publisher   -  person Alexander    schedule 08.07.2020
comment
ผู้จัดพิมพ์เป็นการออกแบบที่น่าสนใจและฉันไม่รู้มาก่อน ขอบคุณ ฉันอาจจะใช้มันในโครงการในอนาคตได้ แต่อันนี้ต้องเข้ากันได้กับ 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)

ในผู้จัดการของคุณ เมื่อคุณได้รับการอัปเดตใหม่ ให้วนซ้ำผู้ร่วมประชุมและอัปเดตการโทร

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

เนื่องจากวัตถุลงทะเบียนเป็นข้อมูลอ้างอิงที่อ่อนแอ มันจึงไม่คงอยู่เมื่อวัตถุถูก deinit นอกจากนี้ คุณสามารถยกเลิกการลงทะเบียนใน deinit ของวัตถุเหล่านั้นได้ แต่นั่นไม่จำเป็น

person Tomo Norbert    schedule 08.07.2020