Я ищу более короткий / лучший способ получить первый объект и NSSet в моем приложении Core Data

В настоящее время у меня есть этот код:

if let myPhoneNumbers = person.phoneNumbers?.allObjects as? [PhoneNumber] {
        for myPhoneNumber in myPhoneNumbers {
        mainPhoneNumber = myPhoneNumber.number
        break
    }
}

Это правильный способ кодирования этого. я знаю это NSSet неупорядочен и, вероятно, является причиной того, что у него нет собственной реализации .first такие как:

person.phoneNumbers.first

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

2 ответа

Решение

В вашем коде myPhoneNumbers это массив, так что вы можете использовать myPhoneNumbers.first вместо зацикливания.

if let myPhoneNumbers = person.phoneNumbers?.allObjects as? [PhoneNumber] {
    mainPhoneNumber = myPhoneNumbers.first
}

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

Поскольку вы упомянули, что используете базовые данные, я предлагаю добавить вспомогательное свойство для вашей сущности Person для возврата телефонных номеров в виде отсортированного массива.

Если ваши сущности выглядят примерно так...

class PhoneNumber: NSManagedObject {
    @NSManaged var number: String
}

class PersonEntity: NSManagedObject {
    @NSManaged var phoneNumbers: NSSet?
}

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

class PersonEntity: NSManagedObject {

    @NSManaged var phoneNumbers: NSSet?

    // Arrays are often easier to work with than sets, 
    //  so provide a convenience property that returns
    //  phone numbers sorted
    var phoneNumbersArray: [PhoneNumber] {
        get {
            if let phoneNumbers = phoneNumbers {
                return (phoneNumbers.allObjects as! [PhoneNumber]).sorted() {
                    // here, sorting by phone number, but
                    // you can sort on whatever you want
                    $1.number > $0.number
                }
            }
            // return empty array if set is nil
            return [PhoneNumber]()
        }
    }
}

Наконец, получите первое число с одной строкой кода следующим образом:

mainPhoneNumber = person.phoneNumbersArray.first

Мне нравится добавлять этот тип удобного массива для всех моих сущностей, у которых есть наборы. С массивами проще работать, на мой взгляд. Здесь я решил вернуть пустой массив вместо массива nil, когда набор равен nil. Это работает, если вы в порядке с лечением ноль и пустых телефонных аппаратов одинаково.

Также обратите внимание, что .first возвращает ноль, если phoneNumbersArray пустой.

Я понятия не имею, почему вы хотели бы получить произвольный "первый" элемент набора, но здесь вы идете:

let first = (person.phoneNumbers?.allObjects as? [PhoneNumber])?.first

Это даст более / менее случайные результаты. Вот мои рекомендации:

  • Храните телефонные номера в массиве, чтобы порядок телефонных номеров пользователя сохранялся.
  • Я думаю, что для пользователя гораздо лучше определить, что составляет основное число. Возможно, хранить ссылку на "основной" PhoneNumber объект внутри Person,
Другие вопросы по тегам