The following code crashes on macOS 15 Sequoia:
import Foundation
let key = NSAttributedString.Key("org.example.key")
let value = Value()
let string = NSMutableAttributedString()
string.append(NSAttributedString(string: "a", attributes: [:]))
string.append(NSAttributedString(string: "b", attributes: [key: value]))
string.append(NSAttributedString(string: "c", attributes: [:]))
string.enumerateAttribute(key, in: NSRange(location: 0, length: string.length)) { value, range, stop in
print(range)
}
class Value: Equatable, Hashable {
static func == (lhs: Value, rhs: Value) -> Bool {
return lhs === rhs
}
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
The error is
EXC_BAD_ACCESS (code=1, address=0x0)
I wanted to run it on my external macOS 14 partition to confirm that it didn't crash before updating to macOS 15, but for some reason macOS will just restart and boot again into macOS 15. So I tried with macOS 13, which I was allowed to start for some reason, and I was able to confirm that the code doesn't crash.
Is this a known issue, and is there a workaround? Removing the two lines that add the letters a and c, or just declaring class Value
without conformance to Equatable, Hashable
, interestingly, solves the issue.
The issue here is that your custom attribute value is a Swift class. If you change it to a subclass of NSObject
, the code runs as expected:
class Value: NSObject {
static func == (lhs: Value, rhs: Value) -> Bool {
return lhs === rhs
}
override var hash: Int {
Int(bitPattern: .init(self))
}
}
I suspect this is fallout from our major rewrite of Foundation. See What’s next for Foundation for more on that.
If this is causing an existing product to fail in the field, I encourage you to file a bug about it. In that case, please post your bug number, just for the record.
If not, subclassing NSObject
seems to be the right choice here for the long term. You are already neck deep in NSXxx
classes anyway.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"