diff --git a/Example/Objective-C/AddressBook.xcodeproj/project.pbxproj b/Example/Objective-C/AddressBook.xcodeproj/project.pbxproj index fdba43c..64e0791 100644 --- a/Example/Objective-C/AddressBook.xcodeproj/project.pbxproj +++ b/Example/Objective-C/AddressBook.xcodeproj/project.pbxproj @@ -7,6 +7,19 @@ objects = { /* Begin PBXBuildFile section */ + 2DBA11BA759966D1EB552C67 /* APAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA10804A06D410681819BD /* APAddress.m */; }; + 2DBA11BEDC2FD17137A8C852 /* APContact.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA14CA55A75A871C26C82F /* APContact.m */; }; + 2DBA1387024AE551F366651B /* APAddressBookBaseRoutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA188046D23F3E87C06E32 /* APAddressBookBaseRoutine.m */; }; + 2DBA16AC68AE7A1C4BC965D0 /* APAddressBookExternalChangeRoutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1AE7B78E62727AC24B8E /* APAddressBookExternalChangeRoutine.m */; }; + 2DBA16D58F1DE05E4754EFC7 /* APAddressBookAccessRoutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1A0BE0B76140D1290AEA /* APAddressBookAccessRoutine.m */; }; + 2DBA17F4EF0FFF28C61A008B /* APThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA19F412AD86EA33259633 /* APThread.m */; }; + 2DBA1A31FBD0315AB086CA73 /* APContactBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA11206A579079E59F2695 /* APContactBuilder.m */; }; + 2DBA1A3CD4061547F5138692 /* NSArray+APAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1196CDD5245AC33DE9AD /* NSArray+APAddressBook.m */; }; + 2DBA1AE11F21966F310307EB /* APAddressBookContactsRoutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA17A4A7B7EA8872870962 /* APAddressBookContactsRoutine.m */; }; + 2DBA1CA49C3A86F1B25376A9 /* APAddressBookRefWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1F56C4DEF9D30603355C /* APAddressBookRefWrapper.m */; }; + 2DBA1CB4F69E60CE1F9C0242 /* APAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA12DDF7D558CB7281DF82 /* APAddressBook.m */; }; + 2DBA1D30942122FA3D996574 /* APSocialProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1825CB9083C503993480 /* APSocialProfile.m */; }; + 2DBA1DD363A02B334F88A6A6 /* APPhoneWithLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DBA1AB470DEA08ACCE65F4A /* APPhoneWithLabel.m */; }; A495CDF35F214F43AFF3AAF9 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6084C3D31A504C79BEA08B84 /* libPods.a */; }; FA66281C187FE9EF00667C81 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA66281B187FE9EF00667C81 /* Foundation.framework */; }; FA66281E187FE9EF00667C81 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA66281D187FE9EF00667C81 /* CoreGraphics.framework */; }; @@ -19,15 +32,38 @@ FA662854187FEC7F00667C81 /* ListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA662853187FEC7F00667C81 /* ListViewController.m */; }; FA662862187FFCA700667C81 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA662861187FFCA700667C81 /* AddressBook.framework */; }; FA66286618800DC500667C81 /* ContactTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FA66286518800DC500667C81 /* ContactTableViewCell.m */; }; - FAB405AF199E5F2000E8E62D /* APAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB405A3199E5F2000E8E62D /* APAddress.m */; }; - FAB405B0199E5F2000E8E62D /* APAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB405A5199E5F2000E8E62D /* APAddressBook.m */; }; - FAB405B1199E5F2000E8E62D /* APContact.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB405A7199E5F2000E8E62D /* APContact.m */; }; - FAB405B2199E5F2000E8E62D /* APPhoneWithLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB405A9199E5F2000E8E62D /* APPhoneWithLabel.m */; }; - FAB405B3199E5F2000E8E62D /* APSocialProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = FAB405AB199E5F2000E8E62D /* APSocialProfile.m */; }; FAD1CCE91881A18900D03475 /* ContactTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FAD1CCE81881A18900D03475 /* ContactTableViewCell.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 2DBA10804A06D410681819BD /* APAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddress.m; sourceTree = ""; }; + 2DBA11206A579079E59F2695 /* APContactBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APContactBuilder.m; sourceTree = ""; }; + 2DBA11341EB34E4C9157C467 /* NSArray+APAddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+APAddressBook.h"; sourceTree = ""; }; + 2DBA1196CDD5245AC33DE9AD /* NSArray+APAddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+APAddressBook.m"; sourceTree = ""; }; + 2DBA12CDF576C49EAEB83108 /* APPhoneWithLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APPhoneWithLabel.h; sourceTree = ""; }; + 2DBA12DDF7D558CB7281DF82 /* APAddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBook.m; sourceTree = ""; }; + 2DBA131ED390B35AF6A6F826 /* APAddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBook.h; sourceTree = ""; }; + 2DBA136C7C8FF0467D706C14 /* APAddressBookAccessRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookAccessRoutine.h; sourceTree = ""; }; + 2DBA1438EC5B589FBE899F88 /* APContactBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APContactBuilder.h; sourceTree = ""; }; + 2DBA14CA55A75A871C26C82F /* APContact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APContact.m; sourceTree = ""; }; + 2DBA161642CBB5F0613EABC7 /* APTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APTypes.h; sourceTree = ""; }; + 2DBA16AB38312AA9DDBD1F1F /* APAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddress.h; sourceTree = ""; }; + 2DBA16B08903C288CE51B171 /* APAddressBookExternalChangeRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookExternalChangeRoutine.h; sourceTree = ""; }; + 2DBA170453898735127CFBB7 /* APAddressBookContactsRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookContactsRoutine.h; sourceTree = ""; }; + 2DBA17A4A7B7EA8872870962 /* APAddressBookContactsRoutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBookContactsRoutine.m; sourceTree = ""; }; + 2DBA1825CB9083C503993480 /* APSocialProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APSocialProfile.m; sourceTree = ""; }; + 2DBA188046D23F3E87C06E32 /* APAddressBookBaseRoutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBookBaseRoutine.m; sourceTree = ""; }; + 2DBA189EB8C378B448163858 /* APAddressBookRefWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookRefWrapper.h; sourceTree = ""; }; + 2DBA19846B6F2A33EDA67564 /* APContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APContact.h; sourceTree = ""; }; + 2DBA19F412AD86EA33259633 /* APThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APThread.m; sourceTree = ""; }; + 2DBA1A0BE0B76140D1290AEA /* APAddressBookAccessRoutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBookAccessRoutine.m; sourceTree = ""; }; + 2DBA1AB470DEA08ACCE65F4A /* APPhoneWithLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APPhoneWithLabel.m; sourceTree = ""; }; + 2DBA1AE7B78E62727AC24B8E /* APAddressBookExternalChangeRoutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBookExternalChangeRoutine.m; sourceTree = ""; }; + 2DBA1C455F191115437B4108 /* APSocialProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APSocialProfile.h; sourceTree = ""; }; + 2DBA1C709D800C9AD2FE62FD /* APAddressBookBaseRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookBaseRoutine.h; sourceTree = ""; }; + 2DBA1EBA78D601335D497A46 /* APAddressBookExternalChangeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBookExternalChangeDelegate.h; sourceTree = ""; }; + 2DBA1F56C4DEF9D30603355C /* APAddressBookRefWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBookRefWrapper.m; sourceTree = ""; }; + 2DBA1FA140934AD39CC7A39C /* APThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APThread.h; sourceTree = ""; }; 6084C3D31A504C79BEA08B84 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 6496F61BD33753BB99E0AB3D /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 8DB33874E6CEAEB5C3CAD23B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; @@ -48,17 +84,6 @@ FA662861187FFCA700667C81 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; FA66286418800DC500667C81 /* ContactTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactTableViewCell.h; sourceTree = ""; }; FA66286518800DC500667C81 /* ContactTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactTableViewCell.m; sourceTree = ""; }; - FAB405A2199E5F2000E8E62D /* APAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddress.h; sourceTree = ""; }; - FAB405A3199E5F2000E8E62D /* APAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddress.m; sourceTree = ""; }; - FAB405A4199E5F2000E8E62D /* APAddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APAddressBook.h; sourceTree = ""; }; - FAB405A5199E5F2000E8E62D /* APAddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APAddressBook.m; sourceTree = ""; }; - FAB405A6199E5F2000E8E62D /* APContact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APContact.h; sourceTree = ""; }; - FAB405A7199E5F2000E8E62D /* APContact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APContact.m; sourceTree = ""; }; - FAB405A8199E5F2000E8E62D /* APPhoneWithLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APPhoneWithLabel.h; sourceTree = ""; }; - FAB405A9199E5F2000E8E62D /* APPhoneWithLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APPhoneWithLabel.m; sourceTree = ""; }; - FAB405AA199E5F2000E8E62D /* APSocialProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APSocialProfile.h; sourceTree = ""; }; - FAB405AB199E5F2000E8E62D /* APSocialProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APSocialProfile.m; sourceTree = ""; }; - FAB405AC199E5F2000E8E62D /* APTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APTypes.h; sourceTree = ""; }; FAD1CCE81881A18900D03475 /* ContactTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactTableViewCell.xib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -78,6 +103,104 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 2DBA10BE344091385DF53A32 /* Public */ = { + isa = PBXGroup; + children = ( + 2DBA131ED390B35AF6A6F826 /* APAddressBook.h */, + 2DBA12DDF7D558CB7281DF82 /* APAddressBook.m */, + 2DBA1D06B4967106F9C2BFBC /* Models */, + ); + path = Public; + sourceTree = ""; + }; + 2DBA112C0378D7B7D3BBC388 /* Thread */ = { + isa = PBXGroup; + children = ( + 2DBA1FA140934AD39CC7A39C /* APThread.h */, + 2DBA19F412AD86EA33259633 /* APThread.m */, + ); + path = Thread; + sourceTree = ""; + }; + 2DBA117066AB2A0303681812 /* Categories */ = { + isa = PBXGroup; + children = ( + 2DBA1196CDD5245AC33DE9AD /* NSArray+APAddressBook.m */, + 2DBA11341EB34E4C9157C467 /* NSArray+APAddressBook.h */, + ); + path = Categories; + sourceTree = ""; + }; + 2DBA17185CB94990CBF52F5E /* Builders */ = { + isa = PBXGroup; + children = ( + 2DBA1438EC5B589FBE899F88 /* APContactBuilder.h */, + 2DBA11206A579079E59F2695 /* APContactBuilder.m */, + ); + path = Builders; + sourceTree = ""; + }; + 2DBA190CE71772B851340885 /* Routine */ = { + isa = PBXGroup; + children = ( + 2DBA1A0BE0B76140D1290AEA /* APAddressBookAccessRoutine.m */, + 2DBA136C7C8FF0467D706C14 /* APAddressBookAccessRoutine.h */, + 2DBA17A4A7B7EA8872870962 /* APAddressBookContactsRoutine.m */, + 2DBA170453898735127CFBB7 /* APAddressBookContactsRoutine.h */, + 2DBA1FD8FF9E5F093B5CC139 /* Base */, + 2DBA1AE7B78E62727AC24B8E /* APAddressBookExternalChangeRoutine.m */, + 2DBA16B08903C288CE51B171 /* APAddressBookExternalChangeRoutine.h */, + 2DBA1EBA78D601335D497A46 /* APAddressBookExternalChangeDelegate.h */, + ); + path = Routine; + sourceTree = ""; + }; + 2DBA195D1571CEBB712DE325 /* Wrapper */ = { + isa = PBXGroup; + children = ( + 2DBA1F56C4DEF9D30603355C /* APAddressBookRefWrapper.m */, + 2DBA189EB8C378B448163858 /* APAddressBookRefWrapper.h */, + ); + path = Wrapper; + sourceTree = ""; + }; + 2DBA1A642E331100BFC32184 /* Private */ = { + isa = PBXGroup; + children = ( + 2DBA112C0378D7B7D3BBC388 /* Thread */, + 2DBA190CE71772B851340885 /* Routine */, + 2DBA17185CB94990CBF52F5E /* Builders */, + 2DBA195D1571CEBB712DE325 /* Wrapper */, + 2DBA117066AB2A0303681812 /* Categories */, + ); + path = Private; + sourceTree = ""; + }; + 2DBA1D06B4967106F9C2BFBC /* Models */ = { + isa = PBXGroup; + children = ( + 2DBA10804A06D410681819BD /* APAddress.m */, + 2DBA16AB38312AA9DDBD1F1F /* APAddress.h */, + 2DBA19846B6F2A33EDA67564 /* APContact.h */, + 2DBA14CA55A75A871C26C82F /* APContact.m */, + 2DBA12CDF576C49EAEB83108 /* APPhoneWithLabel.h */, + 2DBA1AB470DEA08ACCE65F4A /* APPhoneWithLabel.m */, + 2DBA1C455F191115437B4108 /* APSocialProfile.h */, + 2DBA1825CB9083C503993480 /* APSocialProfile.m */, + 2DBA161642CBB5F0613EABC7 /* APTypes.h */, + ); + path = Models; + sourceTree = ""; + }; + 2DBA1FD8FF9E5F093B5CC139 /* Base */ = { + isa = PBXGroup; + children = ( + 2DBA188046D23F3E87C06E32 /* APAddressBookBaseRoutine.m */, + 2DBA1C709D800C9AD2FE62FD /* APAddressBookBaseRoutine.h */, + ); + path = Base; + sourceTree = ""; + }; B1E097FCAF3383FBD1C698F2 /* Pods */ = { isa = PBXGroup; children = ( @@ -206,17 +329,8 @@ FAB405A1199E5F2000E8E62D /* Core */ = { isa = PBXGroup; children = ( - FAB405A2199E5F2000E8E62D /* APAddress.h */, - FAB405A3199E5F2000E8E62D /* APAddress.m */, - FAB405A4199E5F2000E8E62D /* APAddressBook.h */, - FAB405A5199E5F2000E8E62D /* APAddressBook.m */, - FAB405A6199E5F2000E8E62D /* APContact.h */, - FAB405A7199E5F2000E8E62D /* APContact.m */, - FAB405A8199E5F2000E8E62D /* APPhoneWithLabel.h */, - FAB405A9199E5F2000E8E62D /* APPhoneWithLabel.m */, - FAB405AA199E5F2000E8E62D /* APSocialProfile.h */, - FAB405AB199E5F2000E8E62D /* APSocialProfile.m */, - FAB405AC199E5F2000E8E62D /* APTypes.h */, + 2DBA1A642E331100BFC32184 /* Private */, + 2DBA10BE344091385DF53A32 /* Public */, ); path = Core; sourceTree = ""; @@ -322,14 +436,22 @@ buildActionMask = 2147483647; files = ( FA66282C187FE9EF00667C81 /* AppDelegate.m in Sources */, - FAB405AF199E5F2000E8E62D /* APAddress.m in Sources */, FA66286618800DC500667C81 /* ContactTableViewCell.m in Sources */, - FAB405B3199E5F2000E8E62D /* APSocialProfile.m in Sources */, FA662828187FE9EF00667C81 /* main.m in Sources */, - FAB405B2199E5F2000E8E62D /* APPhoneWithLabel.m in Sources */, - FAB405B0199E5F2000E8E62D /* APAddressBook.m in Sources */, FA662854187FEC7F00667C81 /* ListViewController.m in Sources */, - FAB405B1199E5F2000E8E62D /* APContact.m in Sources */, + 2DBA1CB4F69E60CE1F9C0242 /* APAddressBook.m in Sources */, + 2DBA11BA759966D1EB552C67 /* APAddress.m in Sources */, + 2DBA11BEDC2FD17137A8C852 /* APContact.m in Sources */, + 2DBA1DD363A02B334F88A6A6 /* APPhoneWithLabel.m in Sources */, + 2DBA1D30942122FA3D996574 /* APSocialProfile.m in Sources */, + 2DBA17F4EF0FFF28C61A008B /* APThread.m in Sources */, + 2DBA16D58F1DE05E4754EFC7 /* APAddressBookAccessRoutine.m in Sources */, + 2DBA1AE11F21966F310307EB /* APAddressBookContactsRoutine.m in Sources */, + 2DBA1A31FBD0315AB086CA73 /* APContactBuilder.m in Sources */, + 2DBA1CA49C3A86F1B25376A9 /* APAddressBookRefWrapper.m in Sources */, + 2DBA1387024AE551F366651B /* APAddressBookBaseRoutine.m in Sources */, + 2DBA16AC68AE7A1C4BC965D0 /* APAddressBookExternalChangeRoutine.m in Sources */, + 2DBA1A3CD4061547F5138692 /* NSArray+APAddressBook.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/Objective-C/AddressBook/ListViewController.h b/Example/Objective-C/AddressBook/ListViewController.h index fb6b78d..9f0be5d 100644 --- a/Example/Objective-C/AddressBook/ListViewController.h +++ b/Example/Objective-C/AddressBook/ListViewController.h @@ -9,11 +9,5 @@ #import #import "DTTableViewController.h" -@class APAddressBook; - @interface ListViewController : DTTableViewController -{ - APAddressBook *addressBook; -} - @end diff --git a/Example/Objective-C/AddressBook/ListViewController.m b/Example/Objective-C/AddressBook/ListViewController.m index 5ea2d96..567a8ae 100644 --- a/Example/Objective-C/AddressBook/ListViewController.m +++ b/Example/Objective-C/AddressBook/ListViewController.m @@ -13,6 +13,7 @@ @interface ListViewController () @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activity; +@property (nonatomic, strong) APAddressBook *addressBook; @end @implementation ListViewController @@ -24,9 +25,10 @@ - (id)initWithCoder:(NSCoder *)aDecoder self = [super initWithCoder:aDecoder]; if (self) { - addressBook = [[APAddressBook alloc] init]; + self.addressBook = [[APAddressBook alloc] init]; __weak typeof(self) weakSelf = self; - [addressBook startObserveChangesWithCallback:^{ + [self.addressBook startObserveChangesWithCallback:^ + { [weakSelf loadContacts]; }]; } @@ -74,15 +76,15 @@ - (void)loadContacts [self.memoryStorage removeAllTableItems]; [self.activity startAnimating]; __weak __typeof(self) weakSelf = self; - addressBook.fieldsMask = APContactFieldAll; - addressBook.sortDescriptors = @[ + self.addressBook.fieldsMask = APContactFieldAll; + self.addressBook.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"firstName" ascending:YES], [NSSortDescriptor sortDescriptorWithKey:@"lastName" ascending:YES]]; - addressBook.filterBlock = ^BOOL(APContact *contact) + self.addressBook.filterBlock = ^BOOL(APContact *contact) { return contact.phones.count > 0; }; - [addressBook loadContacts:^(NSArray *contacts, NSError *error) + [self.addressBook loadContacts:^(NSArray *contacts, NSError *error) { [weakSelf.activity stopAnimating]; if (!error) @@ -91,10 +93,8 @@ - (void)loadContacts } else { - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil - message:error.localizedDescription - delegate:nil - cancelButtonTitle:@"OK" + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:error.localizedDescription + delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; } diff --git a/Pod/Core/APAddressBook.m b/Pod/Core/APAddressBook.m deleted file mode 100755 index f7db5e9..0000000 --- a/Pod/Core/APAddressBook.m +++ /dev/null @@ -1,189 +0,0 @@ -// -// APAddressBook.m -// APAddressBook -// -// Created by Alexey Belkevich on 1/10/14. -// Copyright (c) 2014 alterplay. All rights reserved. -// - -#import -#import "APAddressBook.h" -#import "APContact.h" - -void APAddressBookExternalChangeCallback(ABAddressBookRef addressBookRef, CFDictionaryRef info, - void *context); - -@interface APAddressBook () -@property (atomic, readonly) ABAddressBookRef addressBook; -@property (nonatomic, copy) void (^changeCallback)(); -@end - -@implementation APAddressBook - -#pragma mark - life cycle - -- (id)init -{ - self = [super init]; - if (self) - { - self.fieldsMask = APContactFieldDefault; - CFErrorRef *error = NULL; - _addressBook = ABAddressBookCreateWithOptions(NULL, error); - if (error) - { - NSString *errorReason = (__bridge_transfer NSString *)CFErrorCopyFailureReason(*error); - NSLog(@"APAddressBook initialization error:\n%@", errorReason); - return nil; - } - } - return self; -} - -- (void)dealloc -{ - [self stopObserveChanges]; - if (_addressBook) - { - CFRelease(_addressBook); - } -} - -#pragma mark - public - -+ (APAddressBookAccess)access -{ - ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); - switch (status) - { - case kABAuthorizationStatusDenied: - case kABAuthorizationStatusRestricted: - return APAddressBookAccessDenied; - - case kABAuthorizationStatusAuthorized: - return APAddressBookAccessGranted; - - default: - return APAddressBookAccessUnknown; - } -} - -+ (void)requestAccess:(void (^)(BOOL granted, NSError * error))completionBlock { - [self requestAccessOnQueue:dispatch_get_main_queue() completion:completionBlock]; -} - -+ (void)requestAccessOnQueue:(dispatch_queue_t)queue - completion:(void (^)(BOOL granted, NSError * error))completionBlock -{ - CFErrorRef *initializationError = NULL; - ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, initializationError); - if (initializationError) - { - - completionBlock ? completionBlock(NO, (__bridge NSError *)(*initializationError)) : nil; - } - else - { - ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) - { - dispatch_async(queue, ^ - { - completionBlock ? completionBlock(granted, (__bridge NSError *)error) : nil; - }); - }); - } - -} - -- (void)loadContacts:(void (^)(NSArray *contacts, NSError *error))completionBlock -{ - [self loadContactsOnQueue:dispatch_get_main_queue() completion:completionBlock]; -} - -- (void)loadContactsOnQueue:(dispatch_queue_t)queue - completion:(void (^)(NSArray *contacts, NSError *error))completionBlock -{ - APContactField fieldMask = self.fieldsMask; - NSArray *descriptors = self.sortDescriptors; - APContactFilterBlock filterBlock = self.filterBlock; - - ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef errorRef) - { - NSArray *array = nil; - NSError *error = nil; - if (granted) - { - __block CFArrayRef peopleArrayRef; - peopleArrayRef = ABAddressBookCopyArrayOfAllPeople(self.addressBook); - NSUInteger contactCount = (NSUInteger)CFArrayGetCount(peopleArrayRef); - NSMutableArray *contacts = [[NSMutableArray alloc] init]; - for (NSUInteger i = 0; i < contactCount; i++) - { - ABRecordRef recordRef = CFArrayGetValueAtIndex(peopleArrayRef, i); - APContact *contact = [[APContact alloc] initWithRecordRef:recordRef - fieldMask:fieldMask]; - if (!filterBlock || filterBlock(contact)) - { - [contacts addObject:contact]; - } - } - [contacts sortUsingDescriptors:descriptors]; - array = contacts.copy; - CFRelease(peopleArrayRef); - } - error = errorRef ? (__bridge NSError *)errorRef : nil; - dispatch_async(queue, ^ - { - completionBlock ? completionBlock(array, error) : nil; - }); - }); -} - -- (void)startObserveChangesWithCallback:(void (^)())callback -{ - if (callback) - { - if (!self.changeCallback) - { - ABAddressBookRegisterExternalChangeCallback(self.addressBook, - APAddressBookExternalChangeCallback, - (__bridge void *)(self)); - } - self.changeCallback = callback; - } -} - -- (void)stopObserveChanges -{ - if (self.changeCallback) - { - self.changeCallback = nil; - ABAddressBookUnregisterExternalChangeCallback(self.addressBook, - APAddressBookExternalChangeCallback, - (__bridge void *)(self)); - } -} - -- (APContact *)getContactByRecordID:(NSNumber *)recordID -{ - APContact *contact = nil; - ABRecordRef ref = ABAddressBookGetPersonWithRecordID(self.addressBook, recordID.intValue); - if (ref != NULL) - { - contact = [[APContact alloc] initWithRecordRef:ref fieldMask:self.fieldsMask]; - } - return contact; -} - -#pragma mark - external change callback - -void APAddressBookExternalChangeCallback(ABAddressBookRef __unused addressBookRef, - CFDictionaryRef __unused info, - void *context) -{ - ABAddressBookRevert(addressBookRef); - APAddressBook *addressBook = (__bridge APAddressBook *)(context); - addressBook.changeCallback ? addressBook.changeCallback() : nil; -} - -@end diff --git a/Pod/Core/APContact.m b/Pod/Core/APContact.m deleted file mode 100755 index ed7b118..0000000 --- a/Pod/Core/APContact.m +++ /dev/null @@ -1,232 +0,0 @@ -// -// APContact.m -// APAddressBook -// -// Created by Alexey Belkevich on 1/10/14. -// Copyright (c) 2014 alterplay. All rights reserved. -// - -#import "APContact.h" -#import "APPhoneWithLabel.h" -#import "APAddress.h" -#import "APSocialProfile.h" - -@implementation APContact - -#pragma mark - life cycle - -- (id)initWithRecordRef:(ABRecordRef)recordRef fieldMask:(APContactField)fieldMask -{ - self = [super init]; - if (self) - { - _fieldMask = fieldMask; - if (fieldMask & APContactFieldFirstName) - { - _firstName = [self stringProperty:kABPersonFirstNameProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldMiddleName) - { - _middleName = [self stringProperty:kABPersonMiddleNameProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldLastName) - { - _lastName = [self stringProperty:kABPersonLastNameProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldCompositeName) - { - _compositeName = [self compositeNameFromRecord:recordRef]; - } - if (fieldMask & APContactFieldCompany) - { - _company = [self stringProperty:kABPersonOrganizationProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldJobTitle) - { - _jobTitle = [self stringProperty:kABPersonJobTitleProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldPhones) - { - _phones = [self arrayProperty:kABPersonPhoneProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldPhonesWithLabels) - { - _phonesWithLabels = [self arrayOfPhonesWithLabelsFromRecord:recordRef]; - } - if (fieldMask & APContactFieldEmails) - { - _emails = [self arrayProperty:kABPersonEmailProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldPhoto) - { - _photo = [self imagePropertyFullSize:YES fromRecord:recordRef]; - } - if (fieldMask & APContactFieldThumbnail) - { - _thumbnail = [self imagePropertyFullSize:NO fromRecord:recordRef]; - } - if (fieldMask & APContactFieldAddresses) - { - NSMutableArray *addresses = [[NSMutableArray alloc] init]; - NSArray *array = [self arrayProperty:kABPersonAddressProperty fromRecord:recordRef]; - for (NSDictionary *dictionary in array) - { - APAddress *address = [[APAddress alloc] initWithAddressDictionary:dictionary]; - [addresses addObject:address]; - } - _addresses = addresses.copy; - } - if (fieldMask & APContactFieldRecordID) - { - _recordID = @(ABRecordGetRecordID(recordRef)); - } - if (fieldMask & APContactFieldCreationDate) - { - _creationDate = [self dateProperty:kABPersonCreationDateProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldModificationDate) - { - _modificationDate = [self dateProperty:kABPersonModificationDateProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldSocialProfiles) - { - NSMutableArray *profiles = [[NSMutableArray alloc] init]; - NSArray *array = [self arrayProperty:kABPersonSocialProfileProperty fromRecord:recordRef]; - for (NSDictionary *dictionary in array) - { - APSocialProfile *profile = [[APSocialProfile alloc] initWithSocialDictionary:dictionary]; - [profiles addObject:profile]; - } - - _socialProfiles = profiles; - } - if (fieldMask & APContactFieldNote) - { - _note = [self stringProperty:kABPersonNoteProperty fromRecord:recordRef]; - } - if (fieldMask & APContactFieldLinkedRecordIDs) - { - NSMutableOrderedSet *linkedRecordIDs = [[NSMutableOrderedSet alloc] init]; - - CFArrayRef linkedPeopleRef = ABPersonCopyArrayOfAllLinkedPeople(recordRef); - CFIndex count = CFArrayGetCount(linkedPeopleRef); - for (CFIndex i = 0; i < count; i++) - { - ABRecordRef linkedRecordRef = CFArrayGetValueAtIndex(linkedPeopleRef, i); - [linkedRecordIDs addObject:@(ABRecordGetRecordID(linkedRecordRef))]; - } - CFRelease(linkedPeopleRef); - - // remove self from linked records - [linkedRecordIDs removeObject:@(ABRecordGetRecordID(recordRef))]; - _linkedRecordIDs = linkedRecordIDs.array; - } - } - return self; -} - -#pragma mark - private - -- (NSString *)stringProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef -{ - CFTypeRef valueRef = (ABRecordCopyValue(recordRef, property)); - return (__bridge_transfer NSString *)valueRef; -} - -- (NSArray *)arrayProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef -{ - NSMutableArray *array = [[NSMutableArray alloc] init]; - [self enumerateMultiValueOfProperty:property fromRecord:recordRef - withBlock:^(ABMultiValueRef multiValue, NSUInteger index) - { - CFTypeRef value = ABMultiValueCopyValueAtIndex(multiValue, index); - NSString *string = (__bridge_transfer NSString *)value; - if (string) - { - [array addObject:string]; - } - }]; - return array.copy; -} - - -- (NSDate *)dateProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef -{ - CFDateRef dateRef = (ABRecordCopyValue(recordRef, property)); - return (__bridge_transfer NSDate *)dateRef; -} - -- (NSArray *)arrayOfPhonesWithLabelsFromRecord:(ABRecordRef)recordRef -{ - NSMutableArray *array = [[NSMutableArray alloc] init]; - [self enumerateMultiValueOfProperty:kABPersonPhoneProperty fromRecord:recordRef - withBlock:^(ABMultiValueRef multiValue, NSUInteger index) - { - CFTypeRef rawPhone = ABMultiValueCopyValueAtIndex(multiValue, index); - NSString *phone = (__bridge_transfer NSString *)rawPhone; - if (phone) - { - NSString *originalLabel = [self originalLabelFromMultiValue:multiValue index:index]; - NSString *localizedLabel = [self localizedLabelFromMultiValue:multiValue index:index]; - APPhoneWithLabel *phoneWithLabel = [[APPhoneWithLabel alloc] initWithPhone:phone originalLabel:originalLabel - localizedLabel:localizedLabel]; - [array addObject:phoneWithLabel]; - } - }]; - return array.copy; -} - -- (UIImage *)imagePropertyFullSize:(BOOL)isFullSize fromRecord:(ABRecordRef)recordRef -{ - ABPersonImageFormat format = isFullSize ? kABPersonImageFormatOriginalSize : - kABPersonImageFormatThumbnail; - NSData *data = (__bridge_transfer NSData *)ABPersonCopyImageDataWithFormat(recordRef, format); - return [UIImage imageWithData:data scale:UIScreen.mainScreen.scale]; -} - -- (NSString *)originalLabelFromMultiValue:(ABMultiValueRef)multiValue index:(NSUInteger)index -{ - NSString *label; - CFTypeRef rawLabel = ABMultiValueCopyLabelAtIndex(multiValue, index); - label = (__bridge_transfer NSString *)rawLabel; - return label; -} - -- (NSString *)localizedLabelFromMultiValue:(ABMultiValueRef)multiValue index:(NSUInteger)index -{ - NSString *label; - CFTypeRef rawLabel = ABMultiValueCopyLabelAtIndex(multiValue, index); - if (rawLabel) - { - CFStringRef localizedLabel = ABAddressBookCopyLocalizedLabel(rawLabel); - if (localizedLabel) - { - label = (__bridge_transfer NSString *)localizedLabel; - } - CFRelease(rawLabel); - } - return label; -} - -- (NSString *)compositeNameFromRecord:(ABRecordRef)recordRef -{ - CFStringRef compositeNameRef = ABRecordCopyCompositeName(recordRef); - return (__bridge_transfer NSString *)compositeNameRef; -} - -- (void)enumerateMultiValueOfProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef - withBlock:(void (^)(ABMultiValueRef multiValue, NSUInteger index))block -{ - ABMultiValueRef multiValue = ABRecordCopyValue(recordRef, property); - if (multiValue) - { - NSUInteger count = (NSUInteger)ABMultiValueGetCount(multiValue); - for (NSUInteger i = 0; i < count; i++) - { - block(multiValue, i); - } - CFRelease(multiValue); - } -} - -@end diff --git a/Pod/Core/Private/Builders/APContactBuilder.h b/Pod/Core/Private/Builders/APContactBuilder.h new file mode 100644 index 0000000..b7c3eba --- /dev/null +++ b/Pod/Core/Private/Builders/APContactBuilder.h @@ -0,0 +1,19 @@ +// +// APContactBuilder +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import +#import "APTypes.h" + +@class APContact; + +@interface APContactBuilder : NSObject + ++ (APContact *)contactWithRecordRef:(ABRecordRef)recordRef fieldMask:(APContactField)fieldMask; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Builders/APContactBuilder.m b/Pod/Core/Private/Builders/APContactBuilder.m new file mode 100644 index 0000000..20c1ef7 --- /dev/null +++ b/Pod/Core/Private/Builders/APContactBuilder.m @@ -0,0 +1,251 @@ +// +// APContactBuilder +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APContactBuilder.h" +#import "APContact.h" +#import "APAddress.h" +#import "APPhoneWithLabel.h" +#import "APSocialProfile.h" + +@interface APContact () +@property (nonatomic, strong) NSString *firstName; +@property (nonatomic, strong) NSString *middleName; +@property (nonatomic, strong) NSString *lastName; +@property (nonatomic, strong) NSString *compositeName; +@property (nonatomic, strong) NSString *company; +@property (nonatomic, strong) NSString *jobTitle; +@property (nonatomic, strong) NSArray *phones; +@property (nonatomic, strong) NSArray *phonesWithLabels; +@property (nonatomic, strong) NSArray *emails; +@property (nonatomic, strong) NSArray *addresses; +@property (nonatomic, strong) UIImage *photo; +@property (nonatomic, strong) UIImage *thumbnail; +@property (nonatomic, strong) NSNumber *recordID; +@property (nonatomic, strong) NSDate *creationDate; +@property (nonatomic, strong) NSDate *modificationDate; +@property (nonatomic, strong) NSArray *socialProfiles; +@property (nonatomic, strong) NSString *note; +@property (nonatomic, strong) NSArray *linkedRecordIDs; +@end + +@implementation APContactBuilder + +#pragma mark - public + ++ (APContact *)contactWithRecordRef:(ABRecordRef)recordRef fieldMask:(APContactField)fieldMask +{ + APContact *contact = [[APContact alloc] init]; + if (fieldMask & APContactFieldFirstName) + { + contact.firstName = [self stringProperty:kABPersonFirstNameProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldMiddleName) + { + contact.middleName = [self stringProperty:kABPersonMiddleNameProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldLastName) + { + contact.lastName = [self stringProperty:kABPersonLastNameProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldCompositeName) + { + contact.compositeName = [self compositeNameFromRecord:recordRef]; + } + if (fieldMask & APContactFieldCompany) + { + contact.company = [self stringProperty:kABPersonOrganizationProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldJobTitle) + { + contact.jobTitle = [self stringProperty:kABPersonJobTitleProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldPhones) + { + contact.phones = [self arrayProperty:kABPersonPhoneProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldPhonesWithLabels) + { + contact.phonesWithLabels = [self arrayOfPhonesWithLabelsFromRecord:recordRef]; + } + if (fieldMask & APContactFieldEmails) + { + contact.emails = [self arrayProperty:kABPersonEmailProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldPhoto) + { + contact.photo = [self imagePropertyFullSize:YES fromRecord:recordRef]; + } + if (fieldMask & APContactFieldThumbnail) + { + contact.thumbnail = [self imagePropertyFullSize:NO fromRecord:recordRef]; + } + if (fieldMask & APContactFieldAddresses) + { + NSMutableArray *addresses = [[NSMutableArray alloc] init]; + NSArray *array = [self arrayProperty:kABPersonAddressProperty fromRecord:recordRef]; + for (NSDictionary *dictionary in array) + { + APAddress *address = [[APAddress alloc] initWithAddressDictionary:dictionary]; + [addresses addObject:address]; + } + contact.addresses = addresses.copy; + } + if (fieldMask & APContactFieldRecordID) + { + contact.recordID = @(ABRecordGetRecordID(recordRef)); + } + if (fieldMask & APContactFieldCreationDate) + { + contact.creationDate = [self dateProperty:kABPersonCreationDateProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldModificationDate) + { + contact.modificationDate = [self dateProperty:kABPersonModificationDateProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldSocialProfiles) + { + NSMutableArray *profiles = [[NSMutableArray alloc] init]; + NSArray *array = [self arrayProperty:kABPersonSocialProfileProperty fromRecord:recordRef]; + for (NSDictionary *dictionary in array) + { + APSocialProfile *profile = [[APSocialProfile alloc] initWithSocialDictionary:dictionary]; + [profiles addObject:profile]; + } + + contact.socialProfiles = profiles; + } + if (fieldMask & APContactFieldNote) + { + contact.note = [self stringProperty:kABPersonNoteProperty fromRecord:recordRef]; + } + if (fieldMask & APContactFieldLinkedRecordIDs) + { + NSMutableOrderedSet *linkedRecordIDs = [[NSMutableOrderedSet alloc] init]; + + CFArrayRef linkedPeopleRef = ABPersonCopyArrayOfAllLinkedPeople(recordRef); + CFIndex count = CFArrayGetCount(linkedPeopleRef); + for (CFIndex i = 0; i < count; i++) + { + ABRecordRef linkedRecordRef = CFArrayGetValueAtIndex(linkedPeopleRef, i); + [linkedRecordIDs addObject:@(ABRecordGetRecordID(linkedRecordRef))]; + } + CFRelease(linkedPeopleRef); + + // remove self from linked records + [linkedRecordIDs removeObject:@(ABRecordGetRecordID(recordRef))]; + contact.linkedRecordIDs = linkedRecordIDs.array; + } + return contact; +} + +#pragma mark - private + ++ (NSString *)stringProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef +{ + CFTypeRef valueRef = (ABRecordCopyValue(recordRef, property)); + return (__bridge_transfer NSString *)valueRef; +} + ++ (NSArray *)arrayProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef +{ + NSMutableArray *array = [[NSMutableArray alloc] init]; + [self enumerateMultiValueOfProperty:property fromRecord:recordRef + withBlock:^(ABMultiValueRef multiValue, NSUInteger index) + { + CFTypeRef value = ABMultiValueCopyValueAtIndex(multiValue, index); + NSString *string = (__bridge_transfer NSString *)value; + if (string) + { + [array addObject:string]; + } + }]; + return array.copy; +} + + ++ (NSDate *)dateProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef +{ + CFDateRef dateRef = (ABRecordCopyValue(recordRef, property)); + return (__bridge_transfer NSDate *)dateRef; +} + ++ (NSArray *)arrayOfPhonesWithLabelsFromRecord:(ABRecordRef)recordRef +{ + NSMutableArray *array = [[NSMutableArray alloc] init]; + [self enumerateMultiValueOfProperty:kABPersonPhoneProperty fromRecord:recordRef + withBlock:^(ABMultiValueRef multiValue, NSUInteger index) + { + CFTypeRef rawPhone = ABMultiValueCopyValueAtIndex(multiValue, index); + NSString *phone = (__bridge_transfer NSString *)rawPhone; + if (phone) + { + NSString *originalLabel = [self originalLabelFromMultiValue:multiValue index:index]; + NSString *localizedLabel = [self localizedLabelFromMultiValue:multiValue index:index]; + APPhoneWithLabel *phoneWithLabel = [[APPhoneWithLabel alloc] initWithPhone:phone originalLabel:originalLabel + localizedLabel:localizedLabel]; + [array addObject:phoneWithLabel]; + } + }]; + return array.copy; +} + ++ (UIImage *)imagePropertyFullSize:(BOOL)isFullSize fromRecord:(ABRecordRef)recordRef +{ + ABPersonImageFormat format = isFullSize ? kABPersonImageFormatOriginalSize : + kABPersonImageFormatThumbnail; + NSData *data = (__bridge_transfer NSData *)ABPersonCopyImageDataWithFormat(recordRef, format); + return [UIImage imageWithData:data scale:UIScreen.mainScreen.scale]; +} + ++ (NSString *)originalLabelFromMultiValue:(ABMultiValueRef)multiValue index:(NSUInteger)index +{ + NSString *label; + CFTypeRef rawLabel = ABMultiValueCopyLabelAtIndex(multiValue, index); + label = (__bridge_transfer NSString *)rawLabel; + return label; +} + ++ (NSString *)localizedLabelFromMultiValue:(ABMultiValueRef)multiValue index:(NSUInteger)index +{ + NSString *label; + CFTypeRef rawLabel = ABMultiValueCopyLabelAtIndex(multiValue, index); + if (rawLabel) + { + CFStringRef localizedLabel = ABAddressBookCopyLocalizedLabel(rawLabel); + if (localizedLabel) + { + label = (__bridge_transfer NSString *)localizedLabel; + } + CFRelease(rawLabel); + } + return label; +} + ++ (NSString *)compositeNameFromRecord:(ABRecordRef)recordRef +{ + CFStringRef compositeNameRef = ABRecordCopyCompositeName(recordRef); + return (__bridge_transfer NSString *)compositeNameRef; +} + ++ (void)enumerateMultiValueOfProperty:(ABPropertyID)property fromRecord:(ABRecordRef)recordRef + withBlock:(void (^)(ABMultiValueRef multiValue, NSUInteger index))block +{ + ABMultiValueRef multiValue = ABRecordCopyValue(recordRef, property); + if (multiValue) + { + NSUInteger count = (NSUInteger)ABMultiValueGetCount(multiValue); + for (NSUInteger i = 0; i < count; i++) + { + block(multiValue, i); + } + CFRelease(multiValue); + } +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Categories/NSArray+APAddressBook.h b/Pod/Core/Private/Categories/NSArray+APAddressBook.h new file mode 100644 index 0000000..01ac6f7 --- /dev/null +++ b/Pod/Core/Private/Categories/NSArray+APAddressBook.h @@ -0,0 +1,18 @@ +// +// NSArray(APAddressBook) +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import + +@class APContact; + +@interface NSArray (APAddressBook) + +- (NSArray *)filteredArrayWithBlock:(BOOL (^)(APContact *contact))filterBlock + sortedWithDescriptors:(NSArray *)descriptors; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Categories/NSArray+APAddressBook.m b/Pod/Core/Private/Categories/NSArray+APAddressBook.m new file mode 100644 index 0000000..34f5400 --- /dev/null +++ b/Pod/Core/Private/Categories/NSArray+APAddressBook.m @@ -0,0 +1,39 @@ +// +// NSArray(APAddressBook) +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import "NSArray+APAddressBook.h" +#import "APContact.h" + +@implementation NSArray (APAddressBook) + +- (NSArray *)filteredArrayWithBlock:(BOOL (^)(APContact *contact))filterBlock + sortedWithDescriptors:(NSArray *)descriptors +{ + NSMutableArray *result = [[NSMutableArray alloc] init]; + if (filterBlock) + { + for (APContact *contact in self) + { + if (filterBlock(contact)) + { + [result addObject:contact]; + } + } + } + else + { + [result addObjectsFromArray:self]; + } + if (descriptors) + { + [result sortUsingDescriptors:descriptors]; + } + return result.copy; +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookAccessRoutine.h b/Pod/Core/Private/Routine/APAddressBookAccessRoutine.h new file mode 100644 index 0000000..7382d97 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookAccessRoutine.h @@ -0,0 +1,18 @@ +// +// APAddressBookAccessRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookBaseRoutine.h" +#import "APTypes.h" + +@interface APAddressBookAccessRoutine : APAddressBookBaseRoutine + +- (void)requestAccessWithCompletion:(void (^)(BOOL granted, NSError *error))completionBlock; ++ (APAddressBookAccess)accessStatus; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookAccessRoutine.m b/Pod/Core/Private/Routine/APAddressBookAccessRoutine.m new file mode 100644 index 0000000..6d90bb3 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookAccessRoutine.m @@ -0,0 +1,49 @@ +// +// APAddressBookAccessRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookAccessRoutine.h" +#import "APAddressBookRefWrapper.h" + +@implementation APAddressBookAccessRoutine + +#pragma mark - public + ++ (APAddressBookAccess)accessStatus +{ + ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); + switch (status) + { + case kABAuthorizationStatusDenied: + case kABAuthorizationStatusRestricted: + return APAddressBookAccessDenied; + + case kABAuthorizationStatusAuthorized: + return APAddressBookAccessGranted; + + default: + return APAddressBookAccessUnknown; + } +} + +- (void)requestAccessWithCompletion:(void (^)(BOOL granted, NSError *error))completionBlock +{ + if (!self.wrapper.error) + { + ABAddressBookRequestAccessWithCompletion(self.wrapper.ref, ^(bool granted, CFErrorRef error) + { + completionBlock ? completionBlock(granted, (__bridge NSError *)error) : nil; + }); + } + else + { + completionBlock ? completionBlock(NO, self.wrapper.error) : nil; + } +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookContactsRoutine.h b/Pod/Core/Private/Routine/APAddressBookContactsRoutine.h new file mode 100644 index 0000000..57ad122 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookContactsRoutine.h @@ -0,0 +1,20 @@ +// +// APAddressBookContactsRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookBaseRoutine.h" +#import "APTypes.h" + +@class APContact; + +@interface APAddressBookContactsRoutine : APAddressBookBaseRoutine + +- (NSArray *)allContactsWithContactFieldMask:(APContactField)fieldMask; +- (APContact *)contactByRecordID:(NSNumber *)recordID withFieldMask:(APContactField)fieldMask; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookContactsRoutine.m b/Pod/Core/Private/Routine/APAddressBookContactsRoutine.m new file mode 100644 index 0000000..56de280 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookContactsRoutine.m @@ -0,0 +1,46 @@ +// +// APAddressBookContactsRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookContactsRoutine.h" +#import "APContactBuilder.h" +#import "APAddressBookRefWrapper.h" + +@implementation APAddressBookContactsRoutine + +#pragma mark - public + +- (NSArray *)allContactsWithContactFieldMask:(APContactField)fieldMask +{ + NSMutableArray *contacts = [[NSMutableArray alloc] init]; + if (!self.wrapper.error) + { + CFArrayRef peopleArrayRef = ABAddressBookCopyArrayOfAllPeople(self.wrapper.ref); + CFIndex count = CFArrayGetCount(peopleArrayRef); + for (CFIndex i = 0; i < count; i++) + { + ABRecordRef recordRef = CFArrayGetValueAtIndex(peopleArrayRef, i); + APContact *contact = [APContactBuilder contactWithRecordRef:recordRef fieldMask:fieldMask]; + [contacts addObject:contact]; + } + CFRelease(peopleArrayRef); + } + return contacts.count > 0 ? contacts.copy : nil; +} + +- (APContact *)contactByRecordID:(NSNumber *)recordID withFieldMask:(APContactField)fieldMask +{ + if (!self.wrapper.error) + { + ABRecordRef recordRef = ABAddressBookGetPersonWithRecordID(self.wrapper.ref, recordID.intValue); + return recordRef != NULL ? [APContactBuilder contactWithRecordRef:recordRef fieldMask:fieldMask] : nil; + } + return nil; +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookExternalChangeDelegate.h b/Pod/Core/Private/Routine/APAddressBookExternalChangeDelegate.h new file mode 100644 index 0000000..17198f8 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookExternalChangeDelegate.h @@ -0,0 +1,15 @@ +// +// APAddressBookExternalChangeDelegate +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import + +@protocol APAddressBookExternalChangeDelegate + +- (void)addressBookDidChange; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.h b/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.h new file mode 100644 index 0000000..4656e10 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.h @@ -0,0 +1,17 @@ +// +// APAddressBookExternalChangeRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookBaseRoutine.h" +#import "APAddressBookExternalChangeDelegate.h" + +@interface APAddressBookExternalChangeRoutine : APAddressBookBaseRoutine + +@property (nonatomic, weak) NSObject *delegate; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.m b/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.m new file mode 100644 index 0000000..2ab5045 --- /dev/null +++ b/Pod/Core/Private/Routine/APAddressBookExternalChangeRoutine.m @@ -0,0 +1,57 @@ +// +// APAddressBookExternalChangeRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import "APAddressBookExternalChangeRoutine.h" +#import "APAddressBookRefWrapper.h" + +void APAddressBookExternalChangeCallback(ABAddressBookRef addressBookRef, CFDictionaryRef __unused info, void *context); + +@implementation APAddressBookExternalChangeRoutine + +#pragma mark - life cycle + +- (instancetype)initWithAddressBookRefWrapper:(APAddressBookRefWrapper *)wrapper +{ + self = [super initWithAddressBookRefWrapper:wrapper]; + if (!wrapper.error) + { + [self registerExternalChangeCallback]; + } + return self; +} + +- (void)dealloc +{ + [self unregisterExternalChangeCallback]; +} + +#pragma mark - private + +- (void)registerExternalChangeCallback +{ + ABAddressBookRegisterExternalChangeCallback(self.wrapper.ref, APAddressBookExternalChangeCallback, + (__bridge void *)(self)); +} + +- (void)unregisterExternalChangeCallback +{ + ABAddressBookUnregisterExternalChangeCallback(self.wrapper.ref, APAddressBookExternalChangeCallback, + (__bridge void *)(self)); +} + +#pragma mark - external change callback + +void APAddressBookExternalChangeCallback(ABAddressBookRef addressBookRef, CFDictionaryRef __unused info, void *context) +{ + ABAddressBookRevert(addressBookRef); + APAddressBookExternalChangeRoutine *routine = (__bridge APAddressBookExternalChangeRoutine *)(context); + [routine.delegate addressBookDidChange]; +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.h b/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.h new file mode 100644 index 0000000..463eb0c --- /dev/null +++ b/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.h @@ -0,0 +1,19 @@ +// +// APAddressBookBaseRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import + +@class APAddressBookRefWrapper; + +@interface APAddressBookBaseRoutine : NSObject + +@property (nonatomic, readonly) APAddressBookRefWrapper *wrapper; + +- (instancetype)initWithAddressBookRefWrapper:(APAddressBookRefWrapper *)wrapper; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.m b/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.m new file mode 100644 index 0000000..17cc897 --- /dev/null +++ b/Pod/Core/Private/Routine/Base/APAddressBookBaseRoutine.m @@ -0,0 +1,27 @@ +// +// APAddressBookBaseRoutine +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import "APAddressBookBaseRoutine.h" +#import "APAddressBookRefWrapper.h" + +@interface APAddressBookBaseRoutine () +@property (nonatomic, strong) APAddressBookRefWrapper *wrapper; +@end + +@implementation APAddressBookBaseRoutine + +#pragma mark - life cycle + +- (instancetype)initWithAddressBookRefWrapper:(APAddressBookRefWrapper *)wrapper +{ + self = [super init]; + self.wrapper = wrapper; + return self; +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Thread/APThread.h b/Pod/Core/Private/Thread/APThread.h new file mode 100644 index 0000000..8fcc860 --- /dev/null +++ b/Pod/Core/Private/Thread/APThread.h @@ -0,0 +1,16 @@ +// +// APThread +// APAddressBook +// +// Created by Alexey Belkevich on 20.08.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import + +@interface APThread : NSThread + +- (void)dispatchAsync:(void (^)())block; +- (void)dispatchSync:(void (^)())block; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Thread/APThread.m b/Pod/Core/Private/Thread/APThread.m new file mode 100644 index 0000000..a51ae25 --- /dev/null +++ b/Pod/Core/Private/Thread/APThread.m @@ -0,0 +1,52 @@ +// +// APThread +// APAddressBook +// +// Created by Alexey Belkevich on 20.08.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import "APThread.h" + +@implementation APThread + +#pragma mark - life cycle + +- (void)dealloc +{ + [self cancel]; +} + +#pragma mark - public + +- (void)dispatchAsync:(void (^)())block +{ + [self performSelector:@selector(performBlock:) onThread:self withObject:block waitUntilDone:NO]; +} + +- (void)dispatchSync:(void (^)())block +{ + [self performSelector:@selector(performBlock:) onThread:self withObject:block waitUntilDone:YES]; +} + +#pragma mark - override + +- (void)main +{ + @autoreleasepool + { + while (!self.cancelled) + { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:NSDate.distantFuture]; + } + } +} + +#pragma mark - private + +- (void)performBlock:(void (^)())block +{ + block(); +} + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.h b/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.h new file mode 100644 index 0000000..d5e845d --- /dev/null +++ b/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.h @@ -0,0 +1,17 @@ +// +// APAddressBookRefWrapper +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import +#import + +@interface APAddressBookRefWrapper : NSObject + +@property (nonatomic, readonly) ABAddressBookRef ref; +@property (nonatomic, readonly) NSError *error; + +@end \ No newline at end of file diff --git a/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.m b/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.m new file mode 100644 index 0000000..a8ad044 --- /dev/null +++ b/Pod/Core/Private/Wrapper/APAddressBookRefWrapper.m @@ -0,0 +1,40 @@ +// +// APAddressBookRefWrapper +// AddressBook +// +// Created by Alexey Belkevich on 21.09.15. +// Copyright © 2015 alterplay. All rights reserved. +// + +#import "APAddressBookRefWrapper.h" + +@interface APAddressBookRefWrapper () +@property (nonatomic, assign) ABAddressBookRef ref; +@property (nonatomic, strong) NSError *error; +@end + +@implementation APAddressBookRefWrapper + +#pragma mark - life cycle + +- (id)init +{ + self = [super init]; + CFErrorRef *error = NULL; + self.ref = ABAddressBookCreateWithOptions(NULL, error); + if (error) + { + self.error = (__bridge NSError *)(*error); + } + return self; +} + +- (void)dealloc +{ + if (self.ref) + { + CFRelease(self.ref); + } +} + +@end \ No newline at end of file diff --git a/Pod/Core/APAddressBook.h b/Pod/Core/Public/APAddressBook.h similarity index 73% rename from Pod/Core/APAddressBook.h rename to Pod/Core/Public/APAddressBook.h index 2b96271..c6a23d1 100755 --- a/Pod/Core/APAddressBook.h +++ b/Pod/Core/Public/APAddressBook.h @@ -10,6 +10,7 @@ #import "APTypes.h" @class APContact; +typedef BOOL(^APContactFilterBlock)(APContact *contact); @interface APAddressBook : NSObject @@ -18,17 +19,18 @@ @property (nonatomic, strong) NSArray *sortDescriptors; + (APAddressBookAccess)access; -+ (void)requestAccess:(void (^)(BOOL granted, NSError * error))completionBlock; ++ (void)requestAccess:(void (^)(BOOL granted, NSError *error))completionBlock; + (void)requestAccessOnQueue:(dispatch_queue_t)queue - completion:(void (^)(BOOL granted, NSError * error))completionBlock; + completion:(void (^)(BOOL granted, NSError *error))completionBlock; - (void)loadContacts:(void (^)(NSArray *contacts, NSError *error))completionBlock; - (void)loadContactsOnQueue:(dispatch_queue_t)queue completion:(void (^)(NSArray *contacts, NSError *error))completionBlock; - (void)startObserveChangesWithCallback:(void (^)())callback; +- (void)startObserveChangesOnQueue:(dispatch_queue_t)queue callback:(void (^)())callback; - (void)stopObserveChanges; - (APContact *)getContactByRecordID:(NSNumber *)recordID; -@end +@end \ No newline at end of file diff --git a/Pod/Core/Public/APAddressBook.m b/Pod/Core/Public/APAddressBook.m new file mode 100755 index 0000000..5b0c753 --- /dev/null +++ b/Pod/Core/Public/APAddressBook.m @@ -0,0 +1,151 @@ +// +// APAddressBook.m +// APAddressBook +// +// Created by Alexey Belkevich on 1/10/14. +// Copyright (c) 2014 alterplay. All rights reserved. +// + +#import "APAddressBook.h" +#import "APAddressBookAccessRoutine.h" +#import "APAddressBookContactsRoutine.h" +#import "APAddressBookExternalChangeRoutine.h" +#import "APAddressBookRefWrapper.h" +#import "APThread.h" +#import "NSArray+APAddressBook.h" + +@interface APAddressBook () +@property (nonatomic, strong) APAddressBookAccessRoutine *access; +@property (nonatomic, strong) APAddressBookContactsRoutine *contacts; +@property (nonatomic, strong) APAddressBookExternalChangeRoutine *externalChange; +@property (nonatomic, strong) APThread *thread; +@property (atomic, copy) void (^externalChangeCallback)(); +@property (atomic, strong) dispatch_queue_t externalChangeQueue; +@end + +@implementation APAddressBook + +#pragma mark - life cycle + +- (id)init +{ + self = [super init]; + self.fieldsMask = APContactFieldDefault; + self.thread = [[APThread alloc] init]; + [self.thread start]; + [self.thread dispatchAsync:^ + { + APAddressBookRefWrapper *refWrapper = [[APAddressBookRefWrapper alloc] init]; + if (!refWrapper.error) + { + self.access = [[APAddressBookAccessRoutine alloc] initWithAddressBookRefWrapper:refWrapper]; + self.contacts = [[APAddressBookContactsRoutine alloc] initWithAddressBookRefWrapper:refWrapper]; + self.externalChange = [[APAddressBookExternalChangeRoutine alloc] initWithAddressBookRefWrapper:refWrapper]; + self.externalChange.delegate = self; + } + else + { + NSLog(@"APAddressBook initialization error:\n%@", refWrapper.error); + } + }]; + return self; +} + +- (void)dealloc +{ + [self.thread cancel]; +} + +#pragma mark - public + ++ (APAddressBookAccess)access +{ + return [APAddressBookAccessRoutine accessStatus]; +} + ++ (void)requestAccess:(void (^)(BOOL granted, NSError *error))completionBlock { + [self requestAccessOnQueue:dispatch_get_main_queue() completion:completionBlock]; +} + ++ (void)requestAccessOnQueue:(dispatch_queue_t)queue + completion:(void (^)(BOOL granted, NSError *error))completionBlock +{ + APAddressBookRefWrapper *refWrapper = [[APAddressBookRefWrapper alloc] init]; + APAddressBookAccessRoutine *access = [[APAddressBookAccessRoutine alloc] initWithAddressBookRefWrapper:refWrapper]; + [access requestAccessWithCompletion:^(BOOL granted, NSError *error) + { + dispatch_async(queue, ^ + { + completionBlock ? completionBlock(granted, error) : nil; + }); + }]; +} + +- (void)loadContacts:(void (^)(NSArray *contacts, NSError *error))completionBlock +{ + [self loadContactsOnQueue:dispatch_get_main_queue() completion:completionBlock]; +} + +- (void)loadContactsOnQueue:(dispatch_queue_t)queue + completion:(void (^)(NSArray *contacts, NSError *error))completionBlock +{ + NSArray *descriptors = self.sortDescriptors; + APContactFilterBlock filterBlock = self.filterBlock; + APContactField fieldMask = self.fieldsMask; + [self.thread dispatchAsync:^ + { + [self.access requestAccessWithCompletion:^(BOOL granted, NSError *error) + { + [self.thread dispatchAsync:^ + { + NSArray *contacts = granted ? [self.contacts allContactsWithContactFieldMask:fieldMask] : nil; + contacts = [contacts filteredArrayWithBlock:filterBlock sortedWithDescriptors:descriptors]; + dispatch_async(queue, ^ + { + completionBlock ? completionBlock(contacts, error) : nil; + }); + }]; + }]; + }]; +} + +- (void)startObserveChangesWithCallback:(void (^)())callback +{ + [self startObserveChangesOnQueue:nil callback:callback]; +} + +- (void)startObserveChangesOnQueue:(dispatch_queue_t)queue callback:(void (^)())callback +{ + self.externalChangeCallback = callback; + self.externalChangeQueue = queue; +} + +- (void)stopObserveChanges +{ + self.externalChangeCallback = nil; + self.externalChangeQueue = nil; +} + +- (APContact *)getContactByRecordID:(NSNumber *)recordID +{ + APContactField fieldMask = self.fieldsMask; + __block APContact *contact = nil; + [self.thread dispatchSync:^ + { + contact = [self.contacts contactByRecordID:recordID withFieldMask:fieldMask]; + }]; + return contact; +} + +#pragma mark - APAddressBookExternalChangeDelegate + +- (void)addressBookDidChange +{ + dispatch_queue_t queue = self.externalChangeQueue ?: dispatch_get_main_queue(); + dispatch_async(queue, ^ + { + self.externalChangeCallback ? self.externalChangeCallback() : nil; + }); +} + +@end diff --git a/Pod/Core/APAddress.h b/Pod/Core/Public/Models/APAddress.h similarity index 96% rename from Pod/Core/APAddress.h rename to Pod/Core/Public/Models/APAddress.h index 6cf62db..4a09a00 100755 --- a/Pod/Core/APAddress.h +++ b/Pod/Core/Public/Models/APAddress.h @@ -1,6 +1,6 @@ // // APAddress.h -// AddressBook +// APAddressBook // // Created by Alexey Belkevich on 4/19/14. // Copyright (c) 2014 alterplay. All rights reserved. diff --git a/Pod/Core/APAddress.m b/Pod/Core/Public/Models/APAddress.m similarity index 97% rename from Pod/Core/APAddress.m rename to Pod/Core/Public/Models/APAddress.m index 90b16fc..0eb74df 100755 --- a/Pod/Core/APAddress.m +++ b/Pod/Core/Public/Models/APAddress.m @@ -1,6 +1,6 @@ // // APAddress.m -// AddressBook +// APAddressBook // // Created by Alexey Belkevich on 4/19/14. // Copyright (c) 2014 alterplay. All rights reserved. diff --git a/Pod/Core/APContact.h b/Pod/Core/Public/Models/APContact.h similarity index 85% rename from Pod/Core/APContact.h rename to Pod/Core/Public/Models/APContact.h index 4dc1745..490e370 100755 --- a/Pod/Core/APContact.h +++ b/Pod/Core/Public/Models/APContact.h @@ -8,12 +8,9 @@ #import #import -#import -#import "APTypes.h" @interface APContact : NSObject -@property (nonatomic, readonly) APContactField fieldMask; @property (nonatomic, readonly) NSString *firstName; @property (nonatomic, readonly) NSString *middleName; @property (nonatomic, readonly) NSString *lastName; @@ -33,6 +30,4 @@ @property (nonatomic, readonly) NSString *note; @property (nonatomic, readonly) NSArray *linkedRecordIDs; -- (id)initWithRecordRef:(ABRecordRef)recordRef fieldMask:(APContactField)fieldMask; - @end diff --git a/Pod/Core/Public/Models/APContact.m b/Pod/Core/Public/Models/APContact.m new file mode 100755 index 0000000..21cc724 --- /dev/null +++ b/Pod/Core/Public/Models/APContact.m @@ -0,0 +1,33 @@ +// +// APContact.m +// APAddressBook +// +// Created by Alexey Belkevich on 1/10/14. +// Copyright (c) 2014 alterplay. All rights reserved. +// + +#import "APContact.h" + +@interface APContact () +@property (nonatomic, strong) NSString *firstName; +@property (nonatomic, strong) NSString *middleName; +@property (nonatomic, strong) NSString *lastName; +@property (nonatomic, strong) NSString *compositeName; +@property (nonatomic, strong) NSString *company; +@property (nonatomic, strong) NSString *jobTitle; +@property (nonatomic, strong) NSArray *phones; +@property (nonatomic, strong) NSArray *phonesWithLabels; +@property (nonatomic, strong) NSArray *emails; +@property (nonatomic, strong) NSArray *addresses; +@property (nonatomic, strong) UIImage *photo; +@property (nonatomic, strong) UIImage *thumbnail; +@property (nonatomic, strong) NSNumber *recordID; +@property (nonatomic, strong) NSDate *creationDate; +@property (nonatomic, strong) NSDate *modificationDate; +@property (nonatomic, strong) NSArray *socialProfiles; +@property (nonatomic, strong) NSString *note; +@property (nonatomic, strong) NSArray *linkedRecordIDs; +@end + +@implementation APContact +@end diff --git a/Pod/Core/APPhoneWithLabel.h b/Pod/Core/Public/Models/APPhoneWithLabel.h similarity index 100% rename from Pod/Core/APPhoneWithLabel.h rename to Pod/Core/Public/Models/APPhoneWithLabel.h diff --git a/Pod/Core/APPhoneWithLabel.m b/Pod/Core/Public/Models/APPhoneWithLabel.m similarity index 100% rename from Pod/Core/APPhoneWithLabel.m rename to Pod/Core/Public/Models/APPhoneWithLabel.m diff --git a/Pod/Core/APSocialProfile.h b/Pod/Core/Public/Models/APSocialProfile.h similarity index 97% rename from Pod/Core/APSocialProfile.h rename to Pod/Core/Public/Models/APSocialProfile.h index ad2d425..c43059e 100644 --- a/Pod/Core/APSocialProfile.h +++ b/Pod/Core/Public/Models/APSocialProfile.h @@ -1,6 +1,6 @@ // // APSocialContact.h -// SyncBook +// APAddressBook // // Created by David on 2014-08-01. // Copyright (c) 2014 David Muzi. All rights reserved. diff --git a/Pod/Core/APSocialProfile.m b/Pod/Core/Public/Models/APSocialProfile.m similarity index 99% rename from Pod/Core/APSocialProfile.m rename to Pod/Core/Public/Models/APSocialProfile.m index e8914eb..792ea86 100644 --- a/Pod/Core/APSocialProfile.m +++ b/Pod/Core/Public/Models/APSocialProfile.m @@ -1,6 +1,6 @@ // // APSocialContact.m -// SyncBook +// APAddressBook // // Created by David on 2014-08-01. // Copyright (c) 2014 David Muzi. All rights reserved. diff --git a/Pod/Core/APTypes.h b/Pod/Core/Public/Models/APTypes.h similarity index 85% rename from Pod/Core/APTypes.h rename to Pod/Core/Public/Models/APTypes.h index f6d7f89..121d5c2 100644 --- a/Pod/Core/APTypes.h +++ b/Pod/Core/Public/Models/APTypes.h @@ -1,16 +1,11 @@ // // APTypes.h -// AddressBook +// APAddressBook // // Created by Alexey Belkevich on 1/11/14. // Copyright (c) 2014 alterplay. All rights reserved. // -#ifndef AddressBook_APTypes_h -#define AddressBook_APTypes_h - -@class APContact; - typedef NS_ENUM(NSUInteger, APAddressBookAccess) { APAddressBookAccessUnknown = 0, @@ -18,8 +13,6 @@ typedef NS_ENUM(NSUInteger, APAddressBookAccess) APAddressBookAccessDenied = 2 }; -typedef BOOL(^APContactFilterBlock)(APContact *contact); - typedef NS_OPTIONS(NSUInteger , APContactField) { APContactFieldFirstName = 1 << 0, @@ -41,8 +34,6 @@ typedef NS_OPTIONS(NSUInteger , APContactField) APContactFieldLinkedRecordIDs = 1 << 16, APContactFieldJobTitle = 1 << 17, APContactFieldDefault = APContactFieldFirstName | APContactFieldLastName | - APContactFieldPhones, + APContactFieldPhones | APContactFieldRecordID, APContactFieldAll = 0xFFFFFFFF -}; - -#endif +}; \ No newline at end of file