NSMutableArray на игровой площадке, вызывающий ошибки с Xcode 7

У меня есть класс, который получает все коды стран и должен сортировать их по алфавиту. Класс отлично работает в Xcode для ios, но когда я копирую его для тестирования на игровой площадке, я получаю сообщение об ошибке. Смотрите картинку.

Код игровой площадки

Поэтому я удалил весь код, чтобы обнаружить, что NSMutableArray не был объявлен должным образом, поэтому он изменил их на это.

var countries:NSMutableArray = NSMutableArray()
var countryKeys:NSMutableArray = NSMutableArray()
var countryNames:NSMutableArray = NSMutableArray() 

Ошибку убрал, но код не запускается. Без ошибок и без вывода.

Кто-нибудь знает, почему этот код не запускается на игровой площадке? Это ошибка?

Полный код здесь

struct countryCodes{
    var countries:NSMutableArray = NSMutableArray()
    var countryKeys:NSMutableArray = NSMutableArray()
    var countryNames:NSMutableArray = NSMutableArray()

    init(){
        for code in NSLocale.ISOCountryCodes() {
            let id = NSLocale.localeIdentifierFromComponents([NSLocaleCountryCode: code])
            let name = NSLocale(localeIdentifier: "en_UK").displayNameForKey(NSLocaleIdentifier, value: id) ?? "Country not found for code: \(code)"
            self.countries.addObject(["key":id,"value":name])
        }
        self.sortByValue()
    }

    private func sortByValue(){
        let descriptor: NSSortDescriptor = NSSortDescriptor(key: "value", ascending: true)
        extractToArrays(self.countries.sortedArrayUsingDescriptors([descriptor]))
    }

    private func extractToArrays(sortedCountries:NSArray){
        for item in self.countries{
            self.countryKeys.addObject(item["key"] as! String)
            self.countryNames.addObject(item["value"] as! String)
        }
    }
}

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

//: Playground - noun: a place where people can play

import UIKit

var str = "Hello, playground"

Ошибка

file:///Volumes/External/Xcode%20Projects/MyPlayground3.playground/: ошибка: выполнение игровой площадки прервано: выполнение было прервано, причина: EXC_BAD_ACCESS (код = 1, адрес = 0x8).


person Al Martin    schedule 15.09.2015    source источник
comment
Пожалуйста, опубликуйте свой код, чтобы мы могли его протестировать.   -  person Eric Aya    schedule 15.09.2015
comment
У меня работает (скриншот)...   -  person Eric Aya    schedule 15.09.2015
comment
Почему вы используете NSMutableArray вместо массива Swift? Я думаю, что это делает это сложнее, чем должно быть.   -  person Aaron Brager    schedule 15.09.2015
comment
@ЭрикД. Не могу просмотреть ваш скриншот. У меня нет аккаунта эверноут. Интересно, почему он не работает на моей игровой площадке. Может быть, это какая-то проблема с конфигурацией?   -  person Al Martin    schedule 15.09.2015
comment
@AlMartin скриншот   -  person Eric Aya    schedule 15.09.2015
comment
@Аарон Брагер. Вот почему я хочу улучшить его в Playground. Если я смогу заставить его работать. Ха-ха.   -  person Al Martin    schedule 15.09.2015
comment
Я только что попытался открыть новую игровую площадку... см. редактирование.   -  person Al Martin    schedule 15.09.2015
comment
Ваш код отлично работал на моей игровой площадке. Вы используете бета-версию Xcode 7?   -  person Adam    schedule 15.09.2015
comment
Версия 7.0 бета 6 (7A192o)   -  person Al Martin    schedule 15.09.2015
comment
Обновление до ГМ. Задача решена.   -  person Adam    schedule 15.09.2015
comment
В чем разница между 7.1 Beta и 7.0 GM?   -  person Al Martin    schedule 15.09.2015
comment
Основное отличие в том, что 7.1 позволяет создавать приложения для tvOS. Я думаю, есть еще много, проверьте примечания к выпуску.   -  person Adam    schedule 15.09.2015


Ответы (1)


Несколько комментариев.

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

struct CountryCodes {

Держитесь подальше от нетипизированных коллекций, таких как NSArray и NSDictionary. Просто используйте собственные типы коллекций Swift. Итак, countries будет массивом [String : String]:

    var countries = [[String : String]]()

При инициализации нам нужно создать массив и отсортировать его.

    init() {
        for code in NSLocale.ISOCountryCodes() {
            let id = NSLocale.localeIdentifierFromComponents([NSLocaleCountryCode : code])

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

            guard let name = NSLocale(localeIdentifier: "en_UK").displayNameForKey(NSLocaleIdentifier, value: id) else {
                debugPrint("Country not found for code: \(code)")
                break;
            }

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

            countries += [["key":id, "value":name]]
        }

Теперь, когда у вас есть все, отсортируйте по значению:

        countries = countries.sort() { $0["value"] < $1["value"] }
    }

Вычисление ключей и названий стран можно быстро выполнить с помощью map — нет необходимости хранить их в отдельных массивах:

    var keys : [String] {
        return countries.map { $0["key"]! }
    }

    var names : [String] {
        return countries.map { $0["value"]! }
    }
}

Вот полный код, если вы хотите попробовать его на игровой площадке:

struct CountryCodes {
    var countries = [[String : String]]()

    init() {
        for code in NSLocale.ISOCountryCodes() {
            let id = NSLocale.localeIdentifierFromComponents([NSLocaleCountryCode : code])

            guard let name = NSLocale(localeIdentifier: "en_UK").displayNameForKey(NSLocaleIdentifier, value: id) else {
                debugPrint("Country not found for code: \(code)")
                break;
            }

            countries += [["key":id, "value":name]]
        }

        countries = countries.sort() { $0["value"] < $1["value"] }
    }

    var keys : [String] {
        return countries.map { $0["key"]! }
    }

    var names : [String] {
        return countries.map { $0["value"]! }
    }
}

let codes = CountryCodes()
codes.countries
codes.keys
codes.names

Обратите внимание, что в этом коде не используется принудительное приведение типов (as!), которое вызывает сбои из-за логических ошибок. Единственный используемый оператор force (!) находится в геттерах keys и names.

person Aaron Brager    schedule 15.09.2015
comment
Спасибо за это. Я проверю это, когда смогу заставить свою игровую площадку работать. - person Al Martin; 15.09.2015
comment
После загрузки последней бета-версии Xcode 7 я рад сообщить, что теперь она работает. Как и ваш код. Вы также исправили мою проблему с сортировкой имен по алфавиту. Спасибо.. - person Al Martin; 16.09.2015