18

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

我最初的想法是将结构包装在一个类中 - 但是首先使用结构有什么意义。

我是否遗漏了什么,或者这只是将 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
4

1 回答 1

31

问题是原始的 Obj-C 方法需要一个 NSDictionary,它只将对象类型作为键和值,在 Swift 中转换为 [AnyObject: AnyObject],除了 NSDictionary 喜欢将其键与 NSObject 中的 isEqual: 进行比较协议,所以密钥必须是 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 来使其不可变。

于 2015-04-25T13:34:30.337 回答