【问题标题】:How to convert [String : Any] to [NSAttributedStringKey : Any]如何将 [String : Any] 转换为 [NSAttributedStringKey : Any]
【发布时间】:2018-03-12 16:38:23
【问题描述】:

处理一些 objC API,我收到一个 NSDictionary<NSString *, id> *>,它在 Swift 中转换为 [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)
}

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

【问题讨论】:

    标签: swift nsattributedstring swift4


    【解决方案1】:

    NSAttributedStringKeyan initialiser that takes a String,您可以使用Dictionaryinit(uniqueKeysWithValues:) 初始化器来从一个键值元组序列构建一个字典,其中每个键都是唯一的(例如这里的情况)。

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

    例如:

    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 以避免创建不必要的中间数组。

    【讨论】:

    • 谢谢!为了详尽无遗,我还必须进行反向操作([NSAttributedStringKey : Any][String : Any]),在这种情况下是 Dictionary(uniqueKeysWithValues: attr.lazy.map { ($0.key.rawValue, $0.value) })
    • @Hamish 为什么是lazyattr.map { /* ... */ } 在这种情况下不会做同样的事情吗?
    • @MatusalemMarques 会达到相同的结果,但使用 lazy 避免了创建不必要的中间数组(键值对只是迭代一次并插入到新字典中,使用应用给定的转换)。
    【解决方案2】:

    你可以使用

    `NSAttributedStringKey(rawValue: String)`
    

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

    `NSAttributedStringKey(rawValue: fakeAttribute)` 
    

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

    【讨论】:

      【解决方案3】:

      虽然 Hamish 提供了一个完美的 Swift 答案,但请注意最后 I solved 的问题直接在 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-29
        • 1970-01-01
        • 2019-06-08
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        相关资源
        最近更新 更多