Find delegate in swift array of delegates
I want to check if I already have a delegate in my removeDelegate method before removing. How should I do it?
Here's what I have 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 call "contains" with an argument list of type "(@lvalue Array <LocationManagerDelegate>!, LocationManagerDelegate) '
source to share
Update for Swift 3:
Assuming delegates are actually instances of the class, you can require that in the protocol "inherit" from "class":
protocol LocationManagerDelegate: class {
// ...
}
and then use the method index(where:)
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 functions contains()
:
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 use the first one, which requires sequence items to conform to the protocol Equatable
, i.e. they can be compared with ==
.
Assuming delegates are actually instances of the class, you can require that in the protocol "inherit" from "class":
protocol LocationManagerDelegate : class {
// ...
}
and then use the second version contains()
based on predicates using the identity operator ===
:
func removeDelegate(delegate:LocationManagerDelegate) {
if contains(_delegates, { $0 === delegate }) {
// Remove delegate
}
}
To remove an object from an array you will need to get its index so you can use
findIdenticalObject()
from fooobar.com/questions/2185739 / ... :
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)
}
}
source to share
The arguments contains
must implement the Equatable protocol as it is defined as:
public func contains<T:Equatable>(left:[T], right:T) -> Bool
Since there is no way to specify what LocationManagerDelegate
implements Equatable, I don't think you can use it. An obvious attempt:
protocol LocationManagerDelegate : Equatable {
...
}
But it will fail when trying to declare an array, because Equatable uses Self.
Best option I can think of:
func removeDelegate(delegate:LocationManagerDelegate) {
_delegates = filter(_delegates) { return $0 !== delegate }
}
source to share