I want to check if I already have a delegate in my removeDelegate method before removing.
How do I do that?
Here's what I've got so far:
protocol LocationManagerDelegate {
func locationManagerDidUpdateLocation(
oldLocation: CLLocationCoordinate2D,
currentLocation: CLLocationCoordinate2D
)
}
class LocationManager: NSObject {
private var _delegates = [LocationManagerDelegate]()
func removeDelegate(delegate:LocationManagerDelegate) {
if contains(_delegates, delegate) {
// Remove delegate
}
}
}
However, this gives me the following error on the 'if contains' line:
cannot invoke 'contains' with an argument list of type '(@lvalue Array< LocationManagerDelegate >!, LocationManagerDelegate)'
Update for Swift 3:
Assuming that the delegates are actually instances of a class, you could require that in the protocol by "inheriting" from "class":
protocol LocationManagerDelegate: class {
// ...
}
and then use the index(where:)
method, using the "indentitiy operator
===
:
class LocationManager: NSObject {
private var _delegates = [LocationManagerDelegate]()
func removeDelegate(delegate:LocationManagerDelegate) {
if let index = _delegates.index(where: { $0 === delegate }) {
_delegates.remove(at: index)
}
}
}
Old answer (Swift 1):
There are two slightly different contains()
functions:
func contains<S : SequenceType where S.Generator.Element : Equatable>(seq: S, x: S.Generator.Element) -> Bool
func contains<S : SequenceType, L : BooleanType>(seq: S, predicate: (S.Generator.Element) -> L) -> Bool
You are using the first one, which requires that the sequence elements conform to
the Equatable
protocol, i.e. they can be compared with ==
.
Assuming that the delegates are actually instances of a class, you could require
that in the protocol by "inheriting" from "class":
protocol LocationManagerDelegate : class {
// ...
}
and then use the second, predicate-based version of contains()
with the
identity operator ===
:
func removeDelegate(delegate:LocationManagerDelegate) {
if contains(_delegates, { $0 === delegate }) {
// Remove delegate
}
}
To remove the object from the array you'll have to get its index, so you might use
the findIdenticalObject()
function from https://stackoverflow.com/a/25543084/1187415:
func findIdenticalObject<T : AnyObject>(array: [T], value: T) -> Int? {
for (index, elem) in enumerate(array) {
if elem === value {
return index
}
}
return nil
}
and then find and remove from the array with
func removeDelegate(delegate:LocationManagerDelegate) {
if let index = findIdenticalObject(_delegates, delegate) {
_delegates.removeAtIndex(index)
}
}
The arguments to contains
must implement the Equatable protocol since it is defined as:
public func contains<T:Equatable>(left:[T], right:T) -> Bool
Since there's no way to indicate that LocationManagerDelegate
implements Equatable, I don't think you can use it. The obvious attempt would be:
protocol LocationManagerDelegate : Equatable {
...
}
But that will fail when you try to declare the array because Equatable uses Self.
The best option I can come up with is:
func removeDelegate(delegate:LocationManagerDelegate) {
_delegates = filter(_delegates) { return $0 !== delegate }
}
protocol LocationManagerDelegate {
// ...
var index_delegate:Int?{get set}
}
class LocationManager {
private var delegates:[LocationManagerDelegate] = []
func add(delegate: LocationManagerDelegate?){
if let d = delegate {
self.delegates.append(d)
let index = self.delegates.count - 1
self.delegates[index].index_delegate = index
}
}
func remove(delegate: LocationManagerDelegate) {
delegates = delegates.filter({ return $0.index_delegate != delegate.index_delegate })
}
}