Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find delegate in a swift Array of delegates

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)'

like image 493
Tycho Pandelaar Avatar asked Dec 17 '14 19:12

Tycho Pandelaar


1 Answers

Update for Swift 4.2:

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 firstIndex(where:) method, using the "identity operator ===:

class LocationManager: NSObject {
    private var _delegates = [LocationManagerDelegate]()
    
    func removeDelegate(delegate:LocationManagerDelegate) {
        if let index = _delegates.firstIndex(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)
    }
}
like image 92
Martin R Avatar answered Sep 21 '22 01:09

Martin R