Я ищу способ получения добавленных / удаленных / измененных контактов для отправки их на сервер.
Я использовал Realm, поскольку он быстрее, чем coreData, сохраняет контакты и при каждом обновлении, или когдапользователь повторно входит в приложение. Я сравниваю базу данных Realm (резервная копия) с контактами sim, чтобы определить, есть ли изменения (вставка - изменение - удаление) ..
код работает нормально, ноэто не достаточно быстро ..
Я пытался использовать ABAddressBookRegisterExternalChangeCallback в целевом C-файле, но это не было удобно, поскольку он вызывается только тогда, когда пользователь изменяется, когда приложение находится в фоновом режиме, и оно не 'не могу дать мне ничего полезного ...
также я попробовал уведомление CnContactStoredidchange, но оно бесполезно.
вот databaseRealmModel im, использующий полное имя + номер телефона в качестве primaryKey для быстрого извлечения его из базы данных
@objcMembers class RealmModel:Object
{
dynamic var fullName: String = ""
dynamic var phoneNumber: String = ""
dynamic var firstName: String = ""
dynamic var lastName: String = ""
dynamic var middleName: String = ""
dynamic var identifier: String = ""
dynamic var primaryKey :String = ""
@objc dynamic var contactImage: Data? = nil
convenience init(fullName: String, phoneNumber: String,firstName:String,lastName:String,middleName:String,contactImage:Data?,identifier:String)
{
self.init()
self.fullName = fullName
self.phoneNumber = phoneNumber
self.firstName = firstName
self.lastName = lastName
self.middleName = middleName
self.contactImage = contactImage
self.identifier = identifier
self.primaryKey = identifier + phoneNumber
}
override class func primaryKey() -> String? {
return "primaryKey"
}
}
2) вот где я вызываю метод
DispatchQueue.global(qos: .userInteractive).async
{
let start = CFAbsoluteTimeGetCurrent()
Utilities.getCotacts { (added,deleted,modified) in
let diff = CFAbsoluteTimeGetCurrent() - start
print("Realm Took \(diff) seconds")
print( "Realm Added Contacts" + String(added.count))
print("Realm deleted Contacts" + String(deleted.count))
print("Realm modified Contacts" + String(modified.count))
}
3) вот реализация фуnction
class func requestForAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
switch authorizationStatus {
case .authorized:
completionHandler(true)
case .denied, .notDetermined:
self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in
if access {
completionHandler(access)
}
else {
if authorizationStatus == CNAuthorizationStatus.denied {
completionHandler(false)
}
}
})
default:
completionHandler(false)
}
}
class func getCotacts(completionHandler: @escaping (_ addedcontacts: ([RealmModel]),_ deletedContacts: ([RealmModel]),_ modifiedContacts: [RealmModel]) -> Void)
{
var addedContacts = [RealmModel]()
var deletedContacts = [RealmModel]()
var modifiedContacts = [RealmModel]()
self.requestForAccess { (approved) in
if approved == true
{ //getting All contacts in database
let realm = try! Realm()
let Arr = realm.objects(RealmModel.self)
var initialArr = Array.init(Arr)
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactEmailAddressesKey,
CNContactImageDataKey,
CNContactPhoneNumbersKey,CNContactImageDataAvailableKey] as! [CNKeyDescriptor]
let contactFetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)
do {
try! realm.write {
try self.contactStore.enumerateContacts(with: contactFetchRequest) {
contact, stop in
//enumerating through contact list
for number in contact.phoneNumbers
{
let firstName = contact.givenName
let lastName = contact.familyName
let middleName = contact.middleName
let fullName = String(format: "%@%@%@%@%@", arguments: [Utilities.isStringNull(string: contact.givenName) ? "" : contact.givenName, Utilities.isStringNull(string: contact.middleName) ? "" : " ", Utilities.isStringNull(string: contact.middleName) ? "" : contact.middleName, Utilities.isStringNull(string: contact.familyName) ? "" : " ", Utilities.isStringNull(string: contact.familyName) ? "" : contact.familyName])
let phoneNumber = number.value.value(forKey: "digits") as? String
var contactsModel = RealmModel(fullName: fullName, phoneNumber: phoneNumber!, firstName: firstName, lastName: lastName, middleName: middleName,contactImage:contact.imageData,identifier:contact.identifier)
let databaseContact = realm.object(ofType: RealmModel.self, forPrimaryKey:contactsModel.primaryKey)
// contact doesnt exist in database so its a new contact
if(databaseContact == nil) { addedContacts.append(contactsModel)
realm.add(contactsModel,update: false)
//it's new contact no need to set update true
}
else
{ // User exists in Database
if(databaseContact?.fullName != contactsModel.fullName)
{
// if full name has been changed
let indexesOfModifiedNumber = initialArr.indices.filter({ initialArr[$0].primaryKey == contactsModel.primaryKey })
if indexesOfModifiedNumber.count > 0
{
modifiedContacts.append(initialArr[indexesOfModifiedNumber.first!])
initialArr.remove(at:indexesOfModifiedNumber.first!)
databaseContact?.fullName = contactsModel.fullName
}
}
else
{ // No Change and contact is found
let indexesOfModifiedNumber = initialArr.indices.filter({ initialArr[$0].primaryKey == contactsModel.primaryKey })
if (indexesOfModifiedNumber.count > 0)
{
initialArr.remove(at: indexesOfModifiedNumber.first!)
}
}
}
}
}
if initialArr.count > 0
{
// deleted Contacts
deletedContacts = initialArr
for element in deletedContacts
{
realm.delete(element)
}
}
completionHandler(addedContacts,deletedContacts,modifiedContacts)
}
}
}
else
{
print("access not approved")
}
}
}
, поскольку Realm быстрее вводит и извлекает, я не обнаружил большой разницы между ним и coreData. Я тестирую их на телефоне с 6000 контактами. Для завершения основных данных требуется 90 секунд.в то время как царству нужно 70 секунд