Property List

Доброго времени суток, друзья!

Бывают такие случаи, когда нужно хранить статические данные в проекте. Возьмем в пример список моделей ноутбуков 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()
    }
}

Автор статьи Михаил Цейтлин.

Конечный проект

3 Комментария
Комментарии

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: