Swift 5 — Установите переменную в значение plist на основе ключа

#ios #swift #swiftui

Вопрос:

Редактировать: По сути, я не могу понять, как вернуть значение в списке plist на основе ключа.

Я пытаюсь создать приложение для себя в swift, которое на данный момент имеет особый фокус — случайным образом выбрать изображение, которое я поместил в папку «Ресурсы», и показать это изображение. Там будет большое количество этих изображений, поэтому вручную вводить параметры не будет работать.

Шаги, которые, по моему мнению, мне нужны:

  1. пусть переменная A = «Элемент (arc4random_uniform(#))»
  2. пусть переменная B = [Значение из списка, соответствующее ключу из переменной A]
  3. Изображение(переменная B)

Шаг 2-это тот, который я не могу понять.

У меня есть список, который изложен примерно так:

скриншот plist

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

 let variableA = "Item (arc4random_uniform(#))"
// # is the number of images in the plist
 

Я знаю, как создать изображение актива, просто используя приведенное ниже.

 var body: some View {
Image(variableB)
    .resizable()
    .scaledToFit()        
}
 

Чего я не знаю и не могу понять, так это как заставить приложение генерировать случайный «Элемент #» из первой части, затем выбрать соответствующее имя из столбца значений списка, используя «Элемент #» в качестве ключевого столбца, а затем использовать это соответствующее значение имени для создания изображения.

ИЗМЕНИТЬ: Я обновил код, и теперь он выглядит следующим образом. Это выдает ошибку в строке с «do {» , в которой говорится, что «Закрытие, содержащее оператор потока управления, не может использоваться с построителем результатов»ViewBuilder»».

 import SwiftUI
import UIKit

struct ContentView: View {
@State private var variableB = ""
    var body: some View {
        let plist = "All Relics"
        do {
            let array = try PropertyListDecoder().decode([String].self, from: Data(plist.utf8))
            let imageName = array.randomElement()!
            print(imageName)
        } catch { print(error) }
        Image(variableB)
        .onAppear {
            if let array = try? PropertyListDecoder().decode([String].self, from: data),
                let imageName = array.randomElement() {
                    variableB = imageName
            }
         }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
 

Ответ №1:

Прежде всего arc4random_uniform устарел. Начиная с Swift 4 существуют собственные API

Это ваш список, содержащий 3 пункта

 let plist = """
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <string>Some Name</string>
    <string>Some Other Name</string>
    <string>Something Different</string>
</array>
</plist>
"""
 

Просто расшифруйте список с PropertyListDecoder помощью to [String] и получите randomElement()

 do {
    let array = try PropertyListDecoder().decode([String].self, from: Data(plist.utf8))
    let imageName = array.randomElement()!
    print(imageName) 
} catch { print(error) }
 

В среде SwiftUI создайте @State переменную

 @State private var variableB = ""
 

и, например, в .onAppear получить случайную строку и назначить ее variableB ( data является Data представлением списка свойств)

 .onAppear {
     if let url = Bundle.main.url(forResource: "All Relics", withExtension: "plist"),
        let data = try? Data(contentsOf: url),
        let array = try? PropertyListDecoder().decode([String].self, from: data),
        let imageName = array.randomElement() {
            variableB = imageName
    }
 }
 

Комментарии:

1. Я ценю эту информацию. Я попытался собрать все это вместе, но я получаю «Закрытие, содержащее оператор потока управления, не может использоваться с построителем результатов» ViewBuilder «» в строке с «do {«и «Ожидаемое» другое «после условия» охрана «»после строки с» пусть имя_имя = массив.randomElement() {»

2. Моя вина, замени guard на if . Первый фрагмент-это просто пример, который нужно протестировать на игровой площадке.

3. Изменить: Я добавляю свой обновленный код в основной пост. Когда вы говорите, что «первый фрагмент» — это просто пример, вы имеете в виду список или часть » сделать {«? Часть «do {«- единственная, возвращающая ошибку «Закрытие, содержащее оператор потока управления, не может использоваться с построителем результатов» ViewBuilder «» в той же строке. Я попытался погуглить эту точную фразу, но она привела только к одному результату, и я не уверен, что понимаю, что она пытается мне сказать.

4. Вы не можете использовать (весь) первый фрагмент в теле представления SwiftUI. Это просто показывает, как декодировать список

5. Ах. Итак, как же мне тогда это обойти? Фрагменты, которые я собрал вместе, были взяты из учебных пособий, которые я смотрел онлайн и пытался собрать воедино небольшие фрагменты здесь и там.