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
How to Programmatically Change The Xdr Display Reference Mode (Aka Preset) on Macos
Swift Equivalent of Unity3D Coroutines
Swift: Guard Let and Where - The Priority
Stripe API Response: The Data Couldn't Be Read Because It Isn't in The Correct Format
Xcode9/Scenekit - .Dae File Not Loading into Scnscene - Returns Nil
List Scroll Freeze on Catalyst Navigationview
How to Put Gamecenter on Application with Swift
How to Make a Function Operate on a Sequence of Optional Values
Drawing at Cocoa with Swift Creates an Error
How to Refer to a Global Type from Within a Class That Has a Nested Type with The Same Name
How to Create Viewcontrollers Without Storyboard and Set One as Delegate of The Other One
Create Custom Action in a Class for Use in Interface Builder
Tintcolor Not Changing for UIbarbuttonitem for .Normal Stage in Case of iOS 13.2
How to Change an Inout Parameter from Within a Escaping Closure
How to Delay a for Loop in Swift Without Interrupting The Main Thread
Swift Casting Generic to Optional with a Nil Value Causes Fatalerror