NSNotificationCenter 将结构作为 UserInfo 的一部分传递

NSNotificationCenter passing structs as part of the UserInfo

由于 NSNotificationCenter.defaultCenter().postNotificationName userinfo 只接受数据符合 AnyObject 协议的字典,有没有人对如何 post 结构作为 NSNotification 的一部分有任何建议?

我最初的想法是将结构包装在 class 中 - 但首先使用结构的意义何在。

我是不是遗漏了什么,或者这只是将 Swift 与为 Objective C 构建的 API 混为一谈的结果?

这是我所描述内容的演示:-

class wrapper: NSObject {

  var aStructToWrap: aStruct

  init(theStruct: aStruct) {

    aStructToWrap = theStruct

    super.init()
  }

}

struct aStruct {
    var aValue: String
}

let aRealStruct = aStruct(aValue: "egg")


NSNotificationCenter.defaultCenter().postNotificationName("aKey", object: nil, userInfo: ["anotherKey": aRealStruct]) // ERR: Extra argument 'userinfo' in call

let wrappedStruct = wrapper(theStruct: aRealStruct)

NSNotificationCenter.defaultCenter().postNotificationName("aKey", object: nil, userInfo: ["anotherKey": wrappedStruct]) // no error

问题是原来的Obj-C方法需要一个NSDictionary,它只接受对象类型作为键和值,翻译成Swift中的[AnyObject: AnyObject],除了NSDictionary喜欢比较它的带有 isEqual: 的键在 NSObject 协议中,因此键必须是 NSObject(我不知道 NSObjectProtocol 是否足够,但 Apple 已决定将其设为 NSObject)。 因此,NSDictionary userInfo 必须是 Swift 中的 [NSObject: AnyObject],因此你不能在其中放置一个结构,我也不相信你可以在 Objective-C 中。

遗憾的是,包装纸将是必要的。我们可以使用 NSValue 并产生一些丑陋且低效的东西,但无论如何最好的解决方案是您创建的包装器。

但是,您创建了 NSObject 的子类,这不是必需的,因此您可以丢弃该代码:)

class Wrapper {
    var aStructToWrap: aStruct
    init(theStruct: aStruct) {
        aStructToWrap = theStruct
    }
}


struct aStruct {
    var aValue: String
}

但我们可以做得更好!我们可以为您喜欢的任何结构或值(甚至对象)制作通用包装器。

class Wrapper<T> {
    var wrappedValue: T
    init(theValue: T) {
        wrappedValue = theValue
    }
}

struct aStruct {
    var aValue: String
}

let aRealStruct = aStruct(aValue: "egg")

let wrappedStruct = Wrapper(theValue: aRealStruct)

NSNotificationCenter.defaultCenter().postNotificationName("aKey", object: nil, userInfo: ["anotherKey": wrappedStruct]) // no error

这是一个可变的包装器,可以通过将 var 换成 let 来使其不可变。