1
votes

XCode 11.2.1
macOS Mojave 10.14.6

So, I'm trying to add the ability to remove objects from an array, if I've kept the reference. Following internet advice, I've caused my protocol to inherit from AnyObject, as this causes/requires/implies === to be defined on any classes that implement the protocol. However, XCode is behaving strangely with the types on the Array extension. Consider that the following compiles fine:

public protocol Foo: AnyObject {
}

public extension Array where Element == Foo {
    mutating func removeElement(element: Element) {
        if let idx = self.firstIndex(where: {$0 === element}) {
            self.remove(at: idx)
        }
    }
}

public func bar(array: [Foo], element: Foo) -> [Foo] {
    var arrayCopy: [Foo] = array
    arrayCopy.removeElement(element: element)
    return arrayCopy
}

but that if I change the extension type to Element: AnyObject, I get a compile error as follows:

...
public extension Array where Element: AnyObject {
...
...
    // Compiler error: '[Foo]' requires that 'Foo' conform to 'AnyObject'
    arrayCopy.removeElement(element: element)
...

Foo DOES conform to AnyObject. It's right there in its definition. Why does XCode not acknowledge this?

1

1 Answers

0
votes

You are using old software so you don't get the modern error message:

Referencing instance method 'removeElement(element:)' on 'Array' requires that 'Foo' be a class type

And that's true. element isn't an instance of a static type, as far as the compiler understands, but it will be if you write it like this instead:

public func bar<Foo: Module.Foo>(array: [Foo], element: Foo) -> [Foo] {

where Module is the actual name of your module, of course.


If you need to use a heterogeneous array, then I don't know how to make things any cleaner than this. Let me know if you figure out better.

(Keep the signature of the function the same; change the body instead.)

var arrayCopy: [AnyObject] = array
arrayCopy.removeElement(element: element)
return arrayCopy as! [Foo]