- Is there a less complicated way to do this?
You could omit self
when accessing the delegates
member, and bake the resulting index of the index(where:)
call into a call to the map
method of Optional
:
func removeDelegate(_ delegate: MyDelegate) {
delegates.index(where: { $0 == delegate})
.map { delegates.remove(at: $0) }
}
In case no such delegate
object is found, the expression above simply results nil
(non-captured result).
This conditional, "{ $0 == delegate }
", is giving causing the error,
"Cannot convert value of type '(OptionalNilComparisonType) -> Bool
' to
expected argument type '() -> Bool
'". How can I fix this? I've tried
adding ?
and !
but still not fully understanding Swift's optional
concept.
This is yet another example of a kind of obscure error message in Swift. The core error is that MyDelegate
does not have an ==
operator defined (does not conform to Equatable
).
After your edit you showed, however, that MyDelegate
is a protocol, so if you let this conform to Equatable
, you wont be able to (as it will be contain a Self
type requirement) use MyDelegate
as a concrete type (only as e.g. type constraint on a generic).
If your concrete delegate objects are reference ones (class
), and you want to test object equality in the sense of testing if both refer to the same object (object reference), you could make use of the the ObjectIdentifier
available to class instances. Constraining MyDelegate
(after your edit you showed it to be a protocol) to only classes,
protocol MyDelegate: class { /* ... */ }
and testing the equality of the ObjectIdentifier
in the index(where:)
call above:
func removeDelegate(_ delegate: MyDelegate) {
delegates.index(where: { ObjectIdentifier($0) == ObjectIdentifier(delegate) })
.map { delegates.remove(at: $0) }
}
Looking at the source code for ObjectIdentifier
, we see that this will compare the underlying raw ptr values of two delegate
instances; from swift/stdlib/public/core/ObjectIdentifier.swift:
public static func == (x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
return Bool(Builtin.cmp_eq_RawPointer(x._value, y._value))
}
As mentioned by @MartinR in the comments to the question above, rather than going via ObjectIdentifier
, you could also use the ===
identity operator for class instances directly.
func removeDelegate(_ delegate: MyDelegate) {
delegates.index(where: { $0 === delegate })
.map { delegates.remove(at: $0) }
}
For completeness, we may verify that ===
make use of the same Builtin
method as the ==
operator for ObjectIdentifier
, by having a look at swift/stdlib/public/core/Equatable.swift:
public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return Bool(Builtin.cmp_eq_RawPointer(
Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
))
case (nil, nil):
return true
default:
return false
}
}