Код: Выделить всё
func compileContactsDataPublisher(contactsArray: [ContactModel]) -> AnyPublisher {
return Just(contactsArray)
.map { contacts -> ContactsCompilation in
var emailToContacts = [String: [ContactModel]]()
var phoneToContacts = [String: [ContactModel]]()
var contactsWithoutDetails = [ContactModel]()
var nameToContacts = [String: [ContactModel]]()
var fullNameToContacts = [String: [ContactModel]]()
var groupedContacts = [String: [ContactModel]]()
var noPhone = [ContactModel]()
var organizations = [ContactModel]()
var jobTitles = [ContactModel]()
var birthdays = [ContactModel]()
var socialAccounts = [ContactModel]()
for contact in contacts {
// 1. Process emails and phones for duplicates
contact.emailAddresses.forEach { email in
emailToContacts[email, default: []].append(contact)
}
contact.phoneNumbers.forEach { phone in
phoneToContacts[phone, default: []].append(contact)
}
// 2. Check for contacts without details
if contact.emailAddresses.isEmpty && contact.phoneNumbers.isEmpty {
contactsWithoutDetails.append(contact)
}
// 3. Group by names for similar names check
[contact.givenName, contact.familyName].forEach { name in
guard !name.isEmpty else { return }
nameToContacts[name, default: []].append(contact)
}
// 4. Group by full name for noName check
let fullName = [contact.givenName, contact.familyName].joined(separator: " ").trimmingCharacters(in: .whitespaces)
let fullNameKey = fullName.isEmpty ? "No Name" : fullName
fullNameToContacts[fullNameKey, default: []].append(contact)
// 5. Generate key for exact duplicates
let exactKey = [
contact.givenName,
contact.middleName,
contact.familyName,
contact.nickname,
contact.organizationName,
contact.jobTitle,
contact.departmentName,
contact.phoneNumbers.joined(separator: ","),
contact.emailAddresses.joined(separator: ",")
].joined(separator: "-")
groupedContacts[exactKey, default: []].append(contact)
// 6. Combined checks
if contact.phoneNumbers.isEmpty {
noPhone.append(contact)
}
if contact.organizationName.count > 1 {
organizations.append(contact)
}
if contact.jobTitle.count > 1 {
jobTitles.append(contact)
}
if contact.birthday != nil {
birthdays.append(contact)
}
if !contact.socialProfiles.isEmpty {
socialAccounts.append(contact)
}
}
// Extract duplicates and groups
let duplicateEmails = emailToContacts.values.filter { $0.count > 1 }
let duplicatePhones = phoneToContacts.values.filter { $0.count > 1 }
let similarNames = nameToContacts.values.filter { $0.count > 1 }
let noName = fullNameToContacts.values.filter { $0.count > 1 }
let duplicates = groupedContacts.values.filter { $0.count > 1 }
return ContactsCompilation(
duplicateEmails: duplicateEmails,
duplicatePhones: duplicatePhones,
contactsWithoutDetails: contactsWithoutDetails,
similarNames: similarNames,
noName: noName,
duplicates: duplicates,
noPhone: noPhone,
organizations: organizations,
jobTitles: jobTitles,
birthdays: birthdays,
socialAccounts: socialAccounts
)
}
.eraseToAnyPublisher()
}
Эта функция работает совершенно хорошо с меньшим количеством контактов, но когда я тестирую с 1000 К контактам 2000 года приложение становится без реагирования и занимает много времени для обработки данных (несколько секунд). секунды, пока мой Реализация занимает значительно дольше. Я подозреваю, что проблема связана с синхронной обработкой в основном потоке, но я не уверен, как ее правильно оптимизировать.
Что я пробовал:
Использование Combine: Функция обернута внутри справедливого и. /> Выполнение вычислений в фоновом потоке: я попытался обернуть операцию внутри dispatchqueue.global (qos: .userinitiated). LI> Оптимизация структур данных: использование словарей для поиска вместо массивов для повышения эффективности. .joined (сепаратор
< /ul>
Вопросы: < /strong> < /p>
Как я могу обработать этот список контактов более эффективно, чтобы предотвратить замораживание пользовательского интерфейса? Br /> < /ul>
Подробнее здесь: https://stackoverflow.com/questions/794 ... i-freezing
Мобильная версия