-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MAPSIOS-1249: Remove duplicated annotations, fix crash (#1981)
- Loading branch information
1 parent
ba7bdc3
commit 1b7dfcc
Showing
18 changed files
with
204 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/// A top-level interface for annotations. | ||
public protocol Annotation { | ||
|
||
/// The unique identifier of the annotation. | ||
var id: String { get } | ||
|
||
/// The geometry that is backing this annotation. | ||
var geometry: Geometry { get } | ||
|
||
/// Properties associated with the annotation. | ||
@available(*, deprecated, message: "Will be deleted in future, for Mapbox-provided annotations see customData instead.") | ||
var userInfo: [String: Any]? { get set } | ||
} | ||
|
||
extension Array where Element: Annotation { | ||
/// Deduplicates annotations. | ||
mutating func removeDuplicates() { | ||
let duplicates = self.removeDuplicates(by: \.id) | ||
if !duplicates.isEmpty { | ||
let ids = duplicates.lazy.map(\.id).joined(separator: ", ") | ||
Log.error(forMessage: "Duplicated annotations: \(ids)", category: "Annotations") | ||
} | ||
} | ||
} | ||
|
||
extension StyleProtocol { | ||
func apply<T: Annotation>(annotationsDiff diff: CollectionDiff<T, String>, sourceId: String, feature: (T) -> Feature) { | ||
if !diff.remove.isEmpty { | ||
removeGeoJSONSourceFeatures(forSourceId: sourceId, featureIds: diff.remove, dataId: nil) | ||
} | ||
if !diff.update.isEmpty { | ||
updateGeoJSONSourceFeatures(forSourceId: sourceId, features: diff.update.map(feature), dataId: nil) | ||
} | ||
if !diff.add.isEmpty { | ||
addGeoJSONSourceFeatures(forSourceId: sourceId, features: diff.add.map(feature), dataId: nil) | ||
} | ||
} | ||
} |
14 changes: 0 additions & 14 deletions
14
Sources/MapboxMaps/Annotations/AnnotationOrchestrator.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 0 additions & 13 deletions
13
Sources/MapboxMaps/Annotations/StyleManager+Extensions.swift
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,50 @@ | ||
struct CollectionDiff<T> { | ||
var remove = [T]() | ||
struct CollectionDiff<T, ID> { | ||
var remove = [ID]() | ||
var update = [T]() | ||
var add = [T]() | ||
|
||
var isEmpty: Bool { remove.isEmpty && update.isEmpty && add.isEmpty } | ||
} | ||
|
||
extension CollectionDiff: Equatable where T: Equatable {} | ||
extension CollectionDiff: Equatable where T: Equatable, ID: Equatable {} | ||
|
||
extension RandomAccessCollection { | ||
/// Returns operations needed to perform in order to get `self` from `old` collection. | ||
/// Treats insertion in the middle as removing all the following elements and re-adding them. | ||
/// Updates element if its `id` and position are the same, but `old != new`. | ||
/// | ||
/// - Complexity: O(n + m), where *n* is length of `self` and *m* is length of `old`. | ||
func diff<ID>(from old: Self, id: (Element) -> ID) -> CollectionDiff<Element> | ||
where ID: Hashable, Element: Equatable { | ||
var result = CollectionDiff<Element>() | ||
|
||
let oldIdsMap = Dictionary(uniqueKeysWithValues: zip(old, old.indices).map { (id($0), $1) }) | ||
func diff<ID>(from old: Self, id getId: (Element) -> ID) -> CollectionDiff<Element, ID> | ||
where ID: Equatable, Element: Equatable { | ||
var result = CollectionDiff<Element, ID>() | ||
|
||
var oldIt = old.startIndex | ||
var it = startIndex | ||
|
||
while oldIt != old.endIndex && it != self.endIndex { | ||
while oldIt != old.endIndex && it != endIndex { | ||
let element = self[it] | ||
let oldElement: Element = old[oldIt] | ||
let newId = id(element) | ||
let oldId = id(oldElement) | ||
let id = getId(element) | ||
|
||
let oldElement = old[oldIt] | ||
let oldId = getId(oldElement) | ||
|
||
if newId == oldId { | ||
if id == oldId { | ||
// The elements are the same, update them if changed. | ||
if oldElement != element { | ||
result.update.append(element) | ||
} | ||
self.formIndex(&it, offsetBy: 1) | ||
formIndex(&it, offsetBy: 1) | ||
old.formIndex(&oldIt, offsetBy: 1) | ||
continue | ||
} | ||
|
||
if let foundOldIt = oldIdsMap[newId], foundOldIt > oldIt { | ||
while oldIt != foundOldIt { | ||
result.remove.append(old[oldIt]) | ||
old.formIndex(&oldIt, offsetBy: 1) | ||
} | ||
oldIt = foundOldIt | ||
continue | ||
} | ||
|
||
break | ||
} | ||
|
||
while it != self.endIndex { | ||
result.add.append(self[it]) | ||
self.formIndex(&it, offsetBy: 1) | ||
} | ||
|
||
while oldIt != old.endIndex { | ||
result.remove.append(old[oldIt]) | ||
result.remove.append(oldId) | ||
old.formIndex(&oldIt, offsetBy: 1) | ||
} | ||
|
||
result.add.append(contentsOf: self[it...]) | ||
result.remove.append(contentsOf: old[oldIt...].lazy.map(getId)) | ||
return result | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
Sources/MapboxMaps/Foundation/Extensions/Array+Extensions.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
extension Array { | ||
/// Removes elements from `self` whose `key` is duplicated with other elements. | ||
/// | ||
/// - Returns: A list of duplicated keys. | ||
mutating func removeDuplicates<Key: Hashable>(by key: (Element) -> Key) -> [Element] { | ||
var keys = Set<Key>() | ||
var duplicates = [Element]() | ||
self.removeAll { el in | ||
let k = key(el) | ||
let isUnique = keys.insert(k).inserted | ||
if !isUnique { | ||
duplicates.append(el) | ||
} | ||
return !isUnique | ||
} | ||
return duplicates | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.