Is it a known bug that ObjC @property (nonatomic, readonly, weak) NSArray<Link *> *links
is imported as [Any]
instead of [Link]
in Swift?
This issue only happens when the property is weak
.
Is it a known bug that ObjC @property (nonatomic, readonly, weak) NSArray<Link *> *links
is imported as [Any]
instead of [Link]
in Swift?
This issue only happens when the property is weak
.
I don’t think that’s a bug. To import this as an Array
you’d need something like:
weak var links: [Link]
but weak
is restricted to classes, and Array
is not a class.
Also, regarding this:
is imported as
[Any]
when I tested this myself (Xcode 26.0.1) I saw it imported as weak var links: NSArray?
, not [Any]
.
Share and Enjoy
Quinn “The Eskimo!” @ DTS @ Apple
You are right. And because lightweight generic cannot be imported as real generic, we don’t have NSArray<Link>
, so can only access elements as Any
.
However, a very insidious issue is this:
if let firstLink = foo.links?.first as? Link {
// do something useful
}
This casting fails! Because somehow, after bridging foo.links
to [Array]
, the first
is resolved to func first(where: (Self.Element) throws -> Bool) rethrows -> Self.Element?
instead of the expected var first: Self.Element?
. This I believe is a real bug.
There is a missing feature here (specifically, a warning when trying to cast a value of function type to a value of a concrete non-function type), but this is actually the language behaving as expected. Your code is not actually bridging to a Swift array (which would be (foo.links as [Any]?)?.first as? Link
, I think), it’s still accessing the actual NSArray
instance. Per the docs, NSArray
only conforms to Sequence
and not Collection
. Collection
is the protocol that exposes var first: Element?
, while Sequence
only exposes the first(where:)
method. To access the first element of an NSArray without bridging, you can use the firstObject
property.
You are right. I later realized that first
comes from Sequence
because when I tried last
I got compiling error.
However, this is truly an issue
There is a missing feature here (specifically, a warning when trying to cast a value of function type to a value of a concrete non-function type)
In fact, after I broken down the optional chaining into
if let foo, let links = foo.links, let firstLink = links.first as? Link
I did got a compiling error:
cast from ' ((NSArray. Element)
throws
Bool)
throws →> NSArray Element?' (aka '((Any) throws -> Bool) throws → Optional<Any>') to unrelated type 'Link' always fails
I think this error should also appear in
if let firstLink = foo?.links?.first as? Link
Agreed — definitely worth opening an issue about. I suspect the issue here is that you’re trying to cast an optional function type to another type, and the type checker doesn’t realize that is also impossible.