3

在处理一些 objC API 时,我收到了一个在 SwiftNSDictionary<NSString *, id> *>中转换为[String : Any]的,我用于NSAttributedString.addAttributes:range:的。

但是,此方法签名现在已随 Xcode 9 更改,现在需要一个[NSAttributedStringKey : Any].

let attr: [String : Any]? = OldPodModule.getMyAttributes()
// Cannot assign value of type '[String : Any]?' to type '[NSAttributedStringKey : Any]?'
let newAttr: [NSAttributedStringKey : Any]? = attr
if let newAttr = newAttr {
    myAttributedString.addAttributes(newAttr, range: range)
}

如何将 a 转换[String : Any]为 a [NSAttributedStringKey : Any]

4

3 回答 3

16

NSAttributedStringKey一个带有 的初始化器,String您可以使用Dictionary' 的init(uniqueKeysWithValues:)初始化器从一系列键值元组构建字典,其中每个键都是唯一的(例如这里的情况)。

我们只需要应用一个转换来attr将每个String键转换NSAttributedStringKey为调用Dictionary的初始化程序之前的一个。

例如:

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)
}

我们在lazy这里使用是为了避免创建不必要的中间数组。

于 2017-06-07T09:48:26.913 回答
0

虽然 Hamish 提供了一个完美的 Swift 答案,但请注意,最后直接在 Objective-C API 级别解决了这个问题。如果您无法控制源代码,也可以使用小型 Objective-C 包装器来完成。

我们简单地替换NSDictionary<NSString *, id> *NSDictionary<NSAttributedStringKey, id> *并添加一个typedef以与早期版本的 Xcode 兼容:

#ifndef NS_EXTENSIBLE_STRING_ENUM
// Compatibility with Xcode 7
#define NS_EXTENSIBLE_STRING_ENUM
#endif

// Testing Xcode version (https://stackoverflow.com/a/46927445/1033581)
#if __clang_major__ < 9
// Compatibility with Xcode 8-
typedef NSString * NSAttributedStringKey NS_EXTENSIBLE_STRING_ENUM;
#endif
于 2018-03-12T08:38:23.527 回答
0

您可以使用

`NSAttributedStringKey(rawValue: String)`

初始化器。但是,有了这个,即使属性字符串不会受到影响,它也会创建一个对象。例如,

`NSAttributedStringKey(rawValue: fakeAttribute)` 

仍会为字典创建一个键。此外,这仅在 iOS 11 中可用,因此请谨慎使用以实现向后兼容性。

于 2017-09-27T01:52:31.703 回答