Доброго времени суток, друзья!
Бывают такие случаи, когда нужно хранить статические данные в проекте. Возьмем в пример список моделей ноутбуков Apple. Да конечно, можно было бы просто создать массив ноутбуков в том контроллере, где он будет использоваться. Но всегда лучше отделять статические данные от кода, особенно если у вас много элементов.
В этом нам поможет Property List.
Использование Property List проще для изменения элементов, менее подвержено ошибкам.
Давайте создадим наш собственный Property List. Создаем новый файл. Выбираем iOS -> Resource -> Property List, как показано ниже, и даем название.
Чтобы добавить или удалить строки, нажмите соответствующие кнопки. Мы создадим массив с названиями моделей ноутбуков Apple.
Наш файл Property List будет выглядеть следующим образом:
Согласитесь, что подобный массив в коде занимал бы довольно много места.
Существует 7 типом данных, которые мы можем сохранять в Property List:
-
- Array (Массив)
- Dictionary (Словарь)
- Boolean
- Data
- Date
- Number
- String
В большинстве случаев файл .plist представляет собой файл XML, хранящийся в виде словаря. Мы можем редактировать Property List либо в редакторе, либо в списках.
Если вы нажмете правой кнопкой на файл и выберете Open As -> Source Code, вы получите совершенно другой вид экрана XML-кода, который будет выглядеть примерно так:
Как работать — решать вам, это дело вкуса. Для начала подойдет стандартный список.
Вначале создадим пустой массив для получения данных (var arrayOfMacbooks = [String]()).
Теперь давайте все-таки достанем данные из нашего Property List. Это лучше всего будет сделать в отдельном методе. Назовем его getMacbookArray, который ничего не принимает, и ничего не возвращает.
Сам процесс можно разбить на 4 части:
1. Находим полный путь к нашему ресурсу:
guard let path = Bundle.main.path(forResource: "Property List", ofType: ".plist") else { return }, где forResource - это название нашего файла, а ofType - тип файла.
2. Далее создаем словарь:
guard let dictionary = NSDictionary(contentsOfFile: path) else { return }, с инициализацией по найденному файлу по заданному пути.
3. Вытаскиваем нужный нам словарь по ключу и кастим до нужного типа данных:
guard let arrayOfMacbooks = dictionary.object(forKey: "Macbooks") as? [String] else { return }
4. И последнее присуждаем нашему ранее созданному пустому массиву, новый массив с макбуками.
self.arrayOfMacbooks = arrayOfMacbooks
func getMacbookArray() {
guard let path = Bundle.main.path(forResource: "Property List", ofType: ".plist") else { return }
guard let dictionary = NSDictionary(contentsOfFile: path) else { return }
guard let arrayOfMacbooks = dictionary.object(forKey: "Macbooks") as? [String] else { return }
self.arrayOfMacbooks = arrayOfMacbooks
}
Заметка
Я рекомендую всегда извлекать опциональное значение, для более безопасной работы приложение. Поэтому в нашем случае, если такого файла не существует, либо может ошиблись в названии, мы просто выйдем из метода.
Отлично! Теперь вы знаете, как хранить статические данные в вашем проекте!
Бонус!
Давайте применим наши новые знания и создадим UITextField, где при нажатии вместо клавиатуры будет всплывать UIPickerView, в который будет импортироваться данные из Property List. Подобный ход очень широко используется во многих IOS приложений.
Настройка демо-приложения
Давайте настроим простое приложение с одним экраном, в котором будет один UITextField. Добавляем @IBOutlet в контроллер. И создадим переменную UIPickerView() (var pickerView = UIPickerView()).
Далее нам нужно создать метод (setupUI), который будет настраивать наш UIPickerView и UITextField.
В нем подписываемся под pickerView.delegate = self и pickerView.dataSource = self, для непосредственной работы с UIPickerView.
Подписываемся под macbookTextField.delegate = self для работы с UITextField.
И в конце указываем macbookTextField.inputView = pickerView. InputView - это пользовательский вид ввода для отображения, когда текстовое поле становится активным. Простыми словами при нажатии на macbookTextField, вместо клавиатуры, будет появляться pickerView.
func setupUI() {
pickerView.delegate = self
pickerView.dataSource = self
macbookTextField.delegate = self
macbookTextField.inputView = pickerView
}
Так как мы подписались под наши элементы, нам нужно подписать наш ViewController в случае с pickerVIew - UIPickerViewDelegate, UIPickerViewDataSource. В случае с textField - UITextFiledDelegate.
Начнем с pickerVIew, нам понадобятся 4 метода:
- (обязательный) func numberOfComponents(in pickerView: UIPickerView) -> Int (Возвращает количество компонентов (или «столбцов»), которое должно отображаться в окне) Возвращаем 1
- (обязательный) func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int (Возвращает количество строк для компонента) Возвращаем arrayOfMacbooks.count
- func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? (Возвращает строку, которая используется в качестве заголовка указанной строки компонента.) Возвращаем arrayOfMacbooks[row]
- func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) (Обрабатывает логику нажатия на указанную строку)
Для начала нужно сделать так, чтобы при выборе компонента, у нас прятался pickerView - view.endEditing(true).
И устанавливаем macbookTextField.text = arrayOfMacbooks[row].
Для textField нам понадобится лишь 1 метод:
- func textFieldDidBeginEditing(_ textField: UITextField) (Он сообщает делегату, что редактирование началось в указанном текстовом поле)
В нем указываем pickerView.reloadAllComponents(), который перезагружает все компоненты pickerView.
И самое последнее, нам нужно вызвать методы getMacbookArray() и setupUI() в viewDidLoad().
Наша работа завершена, если вы запустите приложение и коснетесь текстового поля, появится окно выбора вида с нашим списком в нем. Если вы измените выбор, текстовое поле должно обновиться.
Держу пари, вы думали, что это сложнее. Это может послужить отличным способом получения пользовательского ввода, но с нужными вам результатами!
Вот окончательный код:
class ViewController: UIViewController {
var arrayOfMacbooks = [String]()
var pickerView = UIPickerView()
@IBOutlet weak var macbookTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
getMacbookArray()
setupUI()
}
func getMacbookArray() {
guard let path = Bundle.main.path(forResource: "Property List", ofType: ".plist") else { return }
guard let dictionary = NSDictionary(contentsOfFile: path) else { return }
guard let arrayOfMacbooks = dictionary.object(forKey: "Macbooks") as? [String] else { return }
self.arrayOfMacbooks = arrayOfMacbooks
}
func setupUI() {
pickerView.delegate = self
pickerView.dataSource = self
macbookTextField.delegate = self
macbookTextField.inputView = pickerView
}
}
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return arrayOfMacbooks.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return arrayOfMacbooks[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
view.endEditing(true)
macbookTextField.text = arrayOfMacbooks[row]
}
}
extension ViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
pickerView.reloadAllComponents()
}
}
Автор статьи Михаил Цейтлин.