我正在寻找一种获取添加/删除/修改的联系人以将其发送到服务器的方法。
我使用Realm是因为它比coreData更快来保存联系人 每次刷新或用户重新进入应用程序时..我正在将Realm数据库(备份)与sim联系人进行比较,以检测是否有更改(插入-修改-删除)。.
代码运行正常 但这还不够快..
我尝试在目标C文件中使用ABAddressBookRegisterExternalChangeCallback,但它并不方便,因为仅当在后台运行应用程序时更改用户时才调用它,并且它并没有给我任何有用的信息...
我也尝试了CnContactStoredidchange通知,但这没用。
这是使用全名+电话号码作为主键以便从数据库中快速获取它的databaseRealmModel im
@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)这是函数的实现
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秒