Сделать перечисление Swift (2.1) соответствующим AnyObject

У меня есть несколько словарей типов:

public typealias RESTPostDictionary = [RESTPostDictionaryKey : AnyObject]
public typealias RESTRequestDictionary = [RESTRequestDictionaryKey : AnyObject]

Я использую перечисления, потому что хочу, чтобы ключ словаря был только одним из случаев в перечислении:

public enum RESTPostDictionaryKey : String
{
    case Requests = "requests"
}

А также:

public enum RESTRequestDictionaryKey : String
{
    case RequestURI = "request_uri"
    case HTTPMethod = "http_method"
    case DataDictionary = "data_dictionary"
    case RequestIdentifier = "request_identifier"
    case ResponseFormats = "response_formats"
}

Поскольку мое перечисление технически относится к типу String, я полагал, что для компилятора не составит труда получить базовое строковое значение (которое действительно соответствует AnyObject) и использовать его. Но я получаю предупреждение:

Cannot assign value of type ‘Array<RESTRequestDictionary>’ aka … to type 'AnyObject?’

в следующей функции:

class public func postDictionaryWithRequestDictionaries(requestDictionaries: Array<RESTRequestDictionary>) -> RESTPostDictionary
{
    var postDictionary = RESTPostDictionary()

    postDictionary[.Requests] = requestDictionaries

    return postDictionary
}

Есть ли способ сообщить компилятору, чтобы он получил String с помощью протокола или чего-то еще, не полагаясь на грязное и не похожее на Swift значение .rawValue?

Или я что-то не так делаю?


person Adam Carter    schedule 05.11.2015    source источник
comment
Почему вы ограничиваете словарь только объектами? Если вам не нужны только объекты, вы можете просто изменить AnyObject на Any   -  person Kametrixom    schedule 05.11.2015
comment
Я не знал о Any, но когда я использую Any, я не могу использовать словарь как словарь, например, я использую метод NSJSONSerialization.dataWithJSONObject(postDictionary, options: []) и получаю ошибку, что ’RESTPostDictionary’ does not conform to expected type ‘AnyObject’   -  person Adam Carter    schedule 05.11.2015
comment
О да, в таком случае вам придется использовать объекты, Obj-C ничего больше не умеет.   -  person Kametrixom    schedule 05.11.2015


Ответы (3)


Это неправильно:

public typealias RESTPostDictionary = [RESTPostDictionaryKey : AnyObject]

Вы имеете в виду следующее:

public typealias RESTPostDictionary = [String : AnyObject]

Перечисление не является строкой. Но это строка, которую вы собираетесь использовать в качестве ключа.

Когда вы используете регистр enum в качестве ключа, возьмите его rawValue:

postDictionary[RESTRequestDictionaryKey.Requests.rawValue] = requestDictionaries

Так, например, это законно:

enum Keys : String {
    case Key1 = "hey"
    case Key2 = "ho"
    case Key3 = "hey nonny no"
}

var d = [String:AnyObject]()
d[Keys.Key1.rawValue] = 1
d[Keys.Key2.rawValue] = 2
person matt    schedule 05.11.2015
comment
Я понимаю вашу точку зрения, но я бы хотел, чтобы мой RESTPostDictionary использовал только те ключи, которые находятся в перечислении RESTPostDictionaryKey. Я хочу сказать, что это, безусловно, должно работать, поскольку перечисление технически является типом String, который соответствует AnyObject? - person Adam Carter; 05.11.2015
comment
На самом деле вы не понимаете мою точку зрения, потому что я считаю, что перечисление не технически является строкой. Технически это перечисление, которое является совсем другим животным. - person matt; 05.11.2015
comment
Итак, нет другого способа сообщить компилятору, кроме свойства rawValue? - person Adam Carter; 05.11.2015
comment
Я изменил свои перечисления обратно на структуры со статическими константами для каждого ключа. Спасибо за вашу помощь, хотя - person Adam Carter; 05.11.2015
comment
Я нигде не обращался к вам, я благодарен, что вы помогли, и разочарован, что моя идея не сработала. - person Adam Carter; 05.11.2015
comment
Хорошо, тебе нужно перестать пытаться оскорбить себя. Я не отметил его как закрытый из-за моей загруженности. Теперь он отмечен как правильный ответ. Спасибо. - person Adam Carter; 05.11.2015
comment
@Adam Carter, перечисление технически является строкой, мне кажется, это не так. enum E:String означает перечисление с rawValue.Type == String - person user3441734; 08.11.2015

class Box<T> {
  let value: T
  init(value: T) {
    self.value = value
  }
}
NSNotificationCenter.defaultCenter().postNotificationName("foo", object: Box(value: YourOwnStruct())) // OK

Вы можете привести свой каталог struct/enum, если реализуете AnyObjectConvertible для этого типа.

extension YourOwnStruct: AnyObjectConvertible {}

NSNotificationCenter.defaultCenter().postNotificationName("foo", object: YourOwnStruct()) // OK let value = notification.object as? YourOwnStruct

Посмотреть полный ответ/загрузить исходный код из здесь

person ZaEeM ZaFaR    schedule 29.11.2016

почему бы просто не использовать enum в качестве ключа?

import Foundation

enum E:String, CustomStringConvertible {
    var description: String { return self.rawValue }
    case A = "text A"
    case B = "B text"
    case C = "neither A nor B but C"
}

var dict: Dictionary<E, Any> = [:]
dict[E.A] = "alfa"
dict[E.B] = 1
dict[E.C] = NSDate()

dump(dict)

/*
▿ 3 key/value pairs
▿ [0]: (2 elements)
- .0: E.C
- .1: Nov 8, 2015, 11:01 AM
▿ [1]: (2 elements)
- .0: E.A
- .1: alfa
▿ [2]: (2 elements)
- .0: E.B
- .1: 1
*/

print(dict)
// [neither A nor B but C: 2015-11-08 10:02:47 +0000, text A: "alfa", B text: 1]

Объект, который может быть преобразован в JSON, должен иметь следующие свойства:

Объект верхнего уровня — это NSArray или NSDictionary.

Все объекты являются экземплярами NSString, NSNumber, NSArray, NSDictionary или NSNull.

Все ключи словаря являются экземплярами NSString.

Числа не NaN или бесконечность.

import Foundation

enum E:String, CustomStringConvertible {
    var description: String { return self.rawValue }
    case A = "key A"
    case B = "key B"
    case C = "key C"
}

var dict: Dictionary<NSString, AnyObject> = [:]

dict[E.A.description] = "alfa"
dict[E.B.description] = [1,2,3]
dict[E.C.description] = NSDate()

dict is AnyObject // false
let nsdict = dict as NSDictionary
nsdict is AnyObject // true
print(nsdict)

/*

{
    "key A" = alfa;
    "key B" =     (
        1,
        2,
        3
    );
    "key C" = "2015-11-09 23:13:31 +0000";
}
*/
person user3441734    schedule 08.11.2015
comment
Спасибо за идею, но мне компилятор говорит, что этот тип не соответствует AnyObject при использовании его с классом NSJSONSerialization - person Adam Carter; 10.11.2015
comment
Есть ли способ написать расширение, чтобы мой пользовательский тип [StringBasedEnum : AnyObject] соответствовал типу Swift AnyObject? - person Adam Carter; 10.11.2015
comment
теперь я вижу ответ Мэтта. так что вы все знаете... enum это перечисление, а не строка. даже несмотря на то, что ключ в NSDictionary - NSString, вы можете сравнить его с вашими перечислениями. enum со связанным строковым значением работает как ограниченный набор строковых значений. я использую значения перечисления, соответствующие Streamable, в качестве моего «персонала» JSON. сериализация в JSON проста и быстра, я использую свой собственный синтаксический анализатор с прямым сопоставлением с моими перечислениями, совместимыми с Json. все зависит от ваших потребностей, примеров в сети полно - person user3441734; 10.11.2015