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

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
1个回答

31
问题在于原始的Obj-C方法需要一个NSDictionary,该字典只接受对象类型作为键和值,这在Swift中转换为[AnyObject:AnyObject],但是NSDictionary喜欢使用isEqual:来比较其键,该方法在NSObject协议中,因此键必须是NSObject(我不知道NSObjectProtocol是否足够,但Apple已决定将其变成NSObject)。 因此,在Swift中,NSDictionary userInfo必须是[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,可以自由地使其不可变。


我从未使用过泛型,所以花了一些时间来确定如何获取我的结构体。我使用了通知对象,但概念是相同的。如果让包装器项 = 通知对象 as? 包装器<你的结构体>,那么 foo = 包装器项.wrappedValue。 - DogCoffee
当我在AddObserver时,如何获取userinfo字典中的值? - Eddwin Paz
让editedStruct等于payload.userInfo?["approval"] as? Wrapper<aStruct>,要查看值,请打印((editedStruct?.wrappedValue.aValue)! as String)。 - Eddwin Paz
除了使用包装器外,也许返回一个带有扩展函数的包装对象也是不错的选择。 - allenlinli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接