Как заменить / обновить словарь в массиве словарей на основе типа - PullRequest
0 голосов
/ 27 мая 2020

Я получаю ниже JSON ответ от сервера и отображение номера телефона на экране.

Теперь пользователь может изменить / обновить любой номер телефона, поэтому нам нужно обновить конкретный номер мобильного телефона в том же объекте и отправьте его на сервер.

"phone_numbers": [
                {
                    "type": "MOBILE",
                    "number": "8091212121"
                },
                {
                    "type": "HOME",
                    "number": "4161212943"
                },
                {
                    "type": "BUSINESS",
                    "number": "8091212344"
                }
            ]

Мой класс модели выглядит следующим образом:

public struct Contact: Decodable {
    public let phone_numbers: [Phone]?
}

public struct Phone: Decodable {
    public let type: PhoneType?
    public let number: String?
}

Я изо всех сил пытаюсь обновить этот JSON объект для определенного номера телефона.

Например, если я хочу обновить номер БИЗНЕСА только в указанном выше массиве, как лучше это сделать? Я использую XCode 11 и Swift 5.

Ответы [ 3 ]

1 голос
/ 27 мая 2020

Я изо всех сил пытаюсь обновить этот объект JSON для определенного номера телефона.

Он не должен быть объектом JSON, когда вы его обновляете. Думайте о JSON как о формате для передачи данных. После передачи вы должны проанализировать его во что-то, с чем вы можете работать, например, в массив словарей или что-то еще. Если вы это сделали, то вы можете задать следующие c более конкретные вопросы:

  • Как мне найти конкретную c запись в массиве?
  • Как можно Я изменяю поля структуры?
  • Как я могу заменить одну запись в массиве другой?

Посмотрев определения ваших структур, я думаю, что проблема в вас ' Возможно, это связано с тем, как вы их объявили:

public struct Phone: Decodable {
    public let type: PhoneType?
    public let number: String?
}

Поскольку вы использовали let для объявления type и number, эти поля не могут быть изменены после инициализации. Если вы хотите, чтобы поля структуры Phone можно было изменять, вам нужно объявить их с помощью var вместо let.

То же самое верно и для вашей Contact структуры:

public struct Contact: Decodable {
    public let phone_numbers: [Phone]?
}

Вы объявили phone_numbers как неизменяемый массив, потому что вы использовали let вместо var. Если вы хотите иметь возможность добавлять, удалять или изменять массив в phone_numbers, вам нужно вместо этого использовать var.

Объявления структуры, которые у вас есть прямо сейчас, отлично подходят для чтения данных из JSON, потому что все компоненты данных JSON построены с использованием значений из JSON. Но опять же, вам нужно сделать эти структуры изменяемыми, переключившись на объявления var, если вы хотите иметь возможность вносить изменения.

1 голос
/ 27 мая 2020

Поскольку все ваши свойства определены как константы (let), ничего нельзя обновить. Вам необходимо инициализировать и вернуть новый объект Contact с обновленными номерами телефонов.

Если вы измените свойства на var, то вы сможете обновить:

public enum PhoneType: String, Decodable {
    case mobile = "MOBILE"
    case home = "HOME"
    case business = "BUSINESS"
}

public struct Contact: Decodable {
    public var phone_numbers: [Phone]?

    mutating func update(phoneNumber: String, for type: PhoneType) {
        guard let phone_numbers = self.phone_numbers else { return }

        for (i, number) in phone_numbers.enumerated() {
            if number.type ==  type {
                self.phone_numbers![i].number = phoneNumber
            }
        }
    }
}

public struct Phone: Decodable {
    public var type: PhoneType?
    public var number: String?
}

var contact = try! JSONDecoder().decode(Contact.self, from: jsonData)
contact.update(phoneNumber: "123456", for: .business)
1 голос
/ 27 мая 2020

Есть несколько способов приблизиться к этому (я предполагаю, что PhoneType - это перечисление, которое у вас где-то есть)

Вы можете перебирать массив и защищать только бизнес-номера, например

for phone in phone_numbers{
    guard phone.type == .MOBILE else { continue }
    // Code that modifies phone
}

Вы можете фильтровать и перебирать массив, например,

phone_numbers.filter {$0.type == .BUSINESS }.forEach { phone in
// Modify phone here
} 

Затем вы можете изменить правильное значение в массиве с его индексом, например

for (phoneIndex, phone) in phone_numbers.enumerated() {
    guard phone.type == .BUSINESS else { continue }
    phone_numbers[phoneIndex].type = ANOTHER_TYPE
}

Некоторые могут возразить, что второе предпочтительнее первого, потому что это функция более высокого порядка, но в своей повседневной деятельности я склонен использовать оба варианта и считаю, что это дело вкуса

...