Xcode 9: Cannot Convert Value of Type '[String: Any]' to Expected Argument Type '[Nsattributedstringkey: Any]'

Cannot convert value of type '[String : AnyObject]?' to expected argument type '[NSAttributedStringKey : Any]?'

This is a new feature of Swift 4. All the Cocoa methods that take string identifiers and/or dictionary keys now have their own types for the keys. The reason for this is to add a bit of type safety—in the old regime, it was possible to accidentally pass a String constant by mistake that was meant to be used with some other API, but now in Swift 4, this will result in a compilation error.

Change your method signature to:

open class func drawText(context: CGContext, text: String, point: CGPoint,
align: NSTextAlignment, attributes: [NSAttributedString.Key : Any]?)

EDIT: Updated for Swift 4.2! NSAttributedStringKey has been renamed to NSAttributedString.Key.

Swift 4 Cannot convert value of type '[String : AnyObject]?' to expected argument type '[NSAttributedStringKey : Any]?'

It's a type mismatch: [String : AnyObject] is clearly not [NSAttributedStringKey : Any]

⌥-click on NSAttributedStringKey to see the declaration.


The solution is to declare attributes as

var attributes = [NSAttributedStringKey : Any]()

to remove the down cast

 ..., withAttributes: attributes)

and to write simply

attributes = [.foregroundColor: fieldColor,
.font: fieldFont!,
.paragraphStyle: style]

Cannot convert value of type 'NSAttributedString.Key' to expected dictionary key type 'String' error(swift4.2)

In Swift 4.2 you have to use NSAttributedString.Key instead of String

let lineattribute : [NSAttributedString.Key : Any] = [
.foregroundColor : UIColor(hexString: "#0f88b7ff"),
.underlineStyle : NSUnderlineStyle.styleSingle.rawValue
]

let attributeString = NSMutableAttributedString(string: "View traveling details", attributes: lineattribute)

Cannot subscript a value of type '[NSAttributedStringKey : Any]' with an index of type 'String'

In Swift 4 - NSAttributedString representation is changed.

The types are not [String: AnyObject] anymore. Its [NSAttributedStringKey:Any]

So your attributes should accessed like this:

if let attrs = attributes[NSAttributedStringKey.init("YYTextHighlight")] as? YYTextHighlight

How to convert [String : Any] to [NSAttributedStringKey : Any]

NSAttributedStringKey has an initialiser that takes a String, and you can use Dictionary's init(uniqueKeysWithValues:) initialiser in order to build a dictionary from a sequence of key-value tuples where each key is unique (such as is the case here).

We just have to apply a transform to attr that converts each String key into an NSAttributedStringKey prior to calling Dictionary's initialiser.

For example:

let attributes: [String : Any]? = // ...

let attributedString = NSMutableAttributedString(string: "hello world")
let range = NSRange(location: 0, length: attributedString.string.utf16.count)

if let attributes = attributes {
let convertedAttributes = Dictionary(uniqueKeysWithValues:
attributes.lazy.map { (NSAttributedStringKey($0.key), $0.value) }
)
attributedString.addAttributes(convertedAttributes, range: range)
}

We're using lazy here to avoid the creation of an unnecessary intermediate array.

Cannot convert value of type NSAttributedString.DocumentAttributeKey to .DocumentReadingOptionKey

You need to pass one of the available NSAttributedString DocumentType options:


Hypertext Markup Language (HTML) document.

static let html: NSAttributedString.DocumentType

Plain text document.

static let plain: NSAttributedString.DocumentType

Rich text format document.

static let rtf: NSAttributedString.DocumentType

Rich text format with attachments document.

static let rtfd: NSAttributedString.DocumentType

In this case you will need to pass the first one (html) NSAttributedString.DocumentType.html

So the extension updated to Swift 4 should look like this:

extension NSAttributedString {
convenience init(data: Data, documentType: DocumentType, encoding: String.Encoding = .utf8) throws {
try self.init(data: data,
options: [.documentType: documentType,
.characterEncoding: encoding.rawValue],
documentAttributes: nil)
}
convenience init(html data: Data) throws {
try self.init(data: data, documentType: .html)
}
convenience init(txt data: Data) throws {
try self.init(data: data, documentType: .plain)
}
convenience init(rtf data: Data) throws {
try self.init(data: data, documentType: .rtf)
}
convenience init(rtfd data: Data) throws {
try self.init(data: data, documentType: .rtfd)
}
}

extension StringProtocol {
var data: Data { return Data(utf8) }
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: data)
} catch {
print("html error:", error)
return nil
}
}
var htmlDataToString: String? {
return htmlToAttributedString?.string
}
}

extension Data {
var htmlToAttributedString: NSAttributedString? {
do {
return try .init(html: self)
} catch {
print("html error:", error)
return nil
}

}
}

Playground Testing

let htmlString = "<style type=\"text/css\">#red{color:#F00}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"red\" >Red</span><span id=\"green\" > Green </span><span id=\"blue\">Blue</span>"

let htmlData = Data(htmlString.utf8)

htmlString.htmlToAttributedString
htmlData.htmlToAttributedString

Discussion The HTML importer should not be called from a background
thread (that is, the options dictionary includes documentType with a
value of html). It will try to synchronize with the main thread, fail,
and time out. Calling it from the main thread works (but can still
time out if the HTML contains references to external resources, which
should be avoided at all costs). The HTML import mechanism is meant
for implementing something like markdown (that is, text styles,
colors, and so on), not for general HTML import



Related Topics



Leave a reply



Submit