NSNotificationCenter передает структуры как часть UserInfo

Из-за NSNotificationCenter.defaultCenter(). postNotificationName userinfo принимает только словари с данными, соответствующими протоколу AnyObject, есть ли у кого-нибудь предложения, как публиковать структуры как часть NSNotification?

Вначале я подумал, что это нужно, чтобы обернуть структуру в классе, но тогда, какой смысл использовать структуру в первую очередь.

Я что-то упустил или это просто результат объединения Swift с API, созданным для Objective C?

Вот демонстрация того, что я описываю: -

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

Проблема заключается в том, что для исходного метода Obj-C требуется NSDictionary, который принимает только типы объектов в виде ключей и значений, что переводит на [AnyObject: AnyObject] в Swift, за исключением того, что NSDictionary любит сравнивать свои ключи с isEqual: в протоколе NSObject, поэтому ключ должен быть NSObject (я не знаю, достаточно ли NSObjectProtocol, но Apple решила сделать его NSObject). Поэтому пользовательская информация NSDictionary должна быть [NSObject: AnyObject] в Swift, и поэтому вы не можете поместить туда структуру, и я не верю, что вы тоже могли бы в 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.