In case this is useful to someone, this is the workaround I'll be using: ``` class CustomTextStorage: NSTextStorage {
private let backingStore: NSMutableAttributedString // This method should never get called from Objective-C as it doesn't respect // the API contract because of the wrapping in `String`. // // This could get called directly from Swift code when dispatching without // passing by the Objective-C runtime. So it must still produce the right // thing for Swift. override var string: String { return backingStore.string } // Objective-C method implementation for `string` is remapped to this method to // avoid wrapping the result in `String`. With the correct method signature // we can return the backing store string object. var backingNSString: NSString { return backingStore.mutableString } // call once at program initialization: static func fixupStringMethod() { let theClass = CustomTextStorage.self let badStringMeth = class_getInstanceMethod(theClass, #selector(getter: string)) let goodStringMeth = class_getInstanceMethod(theClass, #selector(getter: backingNSString)) let goodImp = method_getImplementation(goodStringMeth) method_setImplementation(badStringMeth, goodImp) } // ... rest of the class goes here ... } ``` > Le 9 févr. 2017 à 18:12, Michel Fortin via swift-users > <swift-users@swift.org> a écrit : > > The `string` property of `NSTextStorage` is of type `String`, but the > contract it must implement is that it should return the backing store of the > attributed string (the underlying `NSMutableString` used as the backing > store). It seems to me that this makes it impossible to implement correctly a > subclass of `NSTextStorage` in Swift, because Swift automatically wraps the > `NSString` into a `String` and the underlying mutable storage is not passed > around. > > Here's the documentation for that method: > https://developer.apple.com/reference/foundation/nsattributedstring/1412616-string > > In case the contract isn't clear from the documentation (it wasn't for me), I > got a confirmation as a response in radar 30314719: >> It’s returning a copy of the backing store, but the contract is actually >> returning the backing store string. The copy storage declaration in the >> property spec is only used for setter implementation. > > So looks like this is impossible to model correctly in Swift due to the > automatic bridging to `String`. Some APIs in AppKit expect the `NSString` > they receive to mutate when mutating the text storage (touch bar suggestions > in `NSTextView`) and will do bad things this isn't the case. > > Obviously, I can work around this by writing some Objective-C code, but it'd > be better if I could avoid splitting the class implementation between two > languages. There's another way using swizzling to map the Objective-C method > to a Swift implementation of the same method that has the correct signature, > and that's probably what I'll end up doing unless a better solution can be > pointed out to me. -- Michel Fortin https://michelf.ca _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users