2016-08-15 6 views
7

Я хочу, чтобы получить адреса из профиля словаря, но я получил ошибку «вводите? не имеет членов подстрочный»тип какой-нибудь? не имеет членов индексных

var address:[[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]] 
var profile:[String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address] 
profile["Addresses"][0]  <-----------------type any? has no subscript members 

Как я могу это исправить и получить адрес? Большое спасибо.

+5

Попробуйте переписать код без использования какого-либо типа. –

+6

. Полагаю, что лучше использовать классы или структуры для адреса и профиля. –

+2

Пожалуйста, не используйте словари, подобные этому. – Alexander

ответ

15

Когда вы подписываете профиль с "Addresses", вы получаете экземпляр Any. Ваш выбор использовать Any, чтобы соответствовать различным типам внутри одного и того же массива, вызвал стирание типа. Вам нужно будет вернуть результат к его реальному типу, [[String: Any]], чтобы он знал, что экземпляр Any представляет Array. Тогда вы будете иметь возможность индексировать его:

func f() { 
    let address: [[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]] 
    let profile: [String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address] 

    guard let addresses = profile["Addresses"] as? [[String: Any]] else { 
     // Either profile["Addresses"] is nil, or it's not a [[String: Any]] 
     // Handle error here 
     return 
    } 

    print(addresses[0]) 
} 

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

В такой ситуации, когда у вас есть словари с фиксированным набором ключей, структуры являются более подходящим выбором. Они строго типизированы, поэтому вам не нужно делать кастинг вверх и вниз от Any, у них лучшая производительность, и с ними гораздо проще работать. Попробуйте это:

struct Address { 
    let address: String 
    let city: String 
    let zip: Int 
} 

struct Profile { 
    let name: String 
    let age: Int 
    let addresses: [Address] 
} 

let addresses = [ 
    Address(
     address: "someLocation" 
     city: "ABC" 
     zip: 123 
    ), 
    Address(
     address: "someLocation" 
     city: "DEF" 
     zip: 456 
    ), 
] 

let profile = Profile(name: "Mir", age: 10, addresses: addresses) 

print(profile.addresses[0]) //much cleaner/easier! 
+0

Спасибо за ваш урок. Ваше объяснение замечательно. Это еще один способ исправить различные типы внутри одного массива? – KKG

+0

Да, это вопрос? – Alexander

+0

Да, есть ли другой способ исправить различные типы внутри одного массива? (Извините, мой английский беден .. :( – KKG

1

Вы должны заново продумать, как вы решили построить adress и profile; см., например, Alexander Momchliov's answer.


Для обсуждения технических вопросов, вы могли извлечь Any членов profile, что вы знаете, чтобы содержать [String: Any] словари, завернутые в Any массиве; путем последовательного попытки преобразования типа из profile["Addresses"] в [Any] с последующим поэлементно (попытки) преобразования в [String: Any]:

if let adressDictsWrapped = profile["Addresses"] as? [Any] { 
    let adressDicts = adressDictsWrapped.flatMap{ $0 as? [String: Any] } 
    print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"] 
    print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"] 
} 

или, без промежуточной стадии ...

if let adressDicts = profile["Addresses"] as? [[String: Any]] { 
    print(adressDicts[0]) // ["Zip": 123, "City": "ABC", "Address": "someLocation"] 
    print(adressDicts[1]) // ["Zip": 456, "City": "DEF", "Address": "someLocation"] 
} 

Но это лишь небольшая урок в попытке типизированного преобразования (-> не делайте этого).

+0

В этом случае вам не нужна плоская карта.Вы можете напрямую (условно) принуждать к '[[String: Any]]' – Alexander

+0

@AlexanderMomchliov да, эта версия включена во второй блок кода в моем ответе (но я включил это всего за 2 минуты до вашего комментария, так что, возможно, это wasn 't там, когда вы начали свой комментарий): первая альтернатива принимает шаг за шагом в том же вложенном порядке 'Any', что были определены исходные переменные' profile' и 'address' (дополнительно явно объяснимо :) – dfri

+0

Ah yeah , это, наверное, то, что произошло. Итеративное литье фактически не является промежуточным этапом. Вниз кастинг всегда постоянное время. Iirc, Только для повышения скорости требуется только цикл, и только в некоторых случаях – Alexander

0

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

var address:[[String : Any]] = [["Address": "someLocation", "City": "ABC","Zip" : 123],["Address": "someLocation", "City": "DEF","Zip" : 456]] 
var profile:[String : Any] = ["Name": "Mir", "Age": 10, "Addresses": address] 
if let allAddresses = profile["Addresses"] as? [[String:Any]] { 
    print("This are all the address \(allAddresses[0])") 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^