├── .gitignore ├── LICENSE ├── PPGetAddressBook.podspec ├── PPGetAddressBook.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── AndyPang.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ ├── duoyi.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── huangqisheng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── AndyPang.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── PPGetAddressBook.xcscheme │ │ └── xcschememanagement.plist │ ├── duoyi.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── PPGetAddressBook.xcscheme │ │ └── xcschememanagement.plist │ └── huangqisheng.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── PPGetAddressBook.xcscheme │ └── xcschememanagement.plist ├── PPGetAddressBook ├── AddressBookController1.h ├── AddressBookController1.m ├── AddressBookController1.xib ├── AddressBookController2.h ├── AddressBookController2.m ├── AddressBookController2.xib ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── PPGetAddressBook │ ├── PPAddressBookHandle.h │ ├── PPAddressBookHandle.m │ ├── PPGetAddressBook.h │ ├── PPGetAddressBook.m │ ├── PPPersonModel.h │ ├── PPPersonModel.m │ └── PPSingleton.h ├── ViewController.h ├── ViewController.m ├── defult.png └── main.m ├── PPGetAddressBookTests ├── Info.plist └── PPGetAddressBookTests.m ├── Picture ├── AddressBook.mov.gif └── PPGetAddressBook.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 jkpang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PPGetAddressBook.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | s.name = "PPGetAddressBook" 5 | s.version = "0.2.8" 6 | s.summary = "一句代码极速获取按A~Z分组精准排序的通讯录联系人 OC版( 已处理姓名所有字符的排序问题 )" 7 | 8 | s.homepage = "https://github.com/jkpang/PPGetAddressBook.git" 9 | 10 | s.license = { :type => "MIT", :file => "LICENSE" } 11 | 12 | s.author = { "jkpang" => "jkpang@outlook.com" } 13 | 14 | s.platform = :ios, "7.0" 15 | 16 | s.source = { :git => "https://github.com/jkpang/PPGetAddressBook.git", :tag => s.version.to_s } 17 | 18 | s.source_files = "PPGetAddressBook/PPGetAddressBook/*.{h,m}" 19 | 20 | s.requires_arc = true 21 | 22 | end 23 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2291AAB41D65EE4A007A923C /* AddressBookController1.m in Sources */ = {isa = PBXBuildFile; fileRef = 2291AAB21D65EE4A007A923C /* AddressBookController1.m */; }; 11 | 2291AAB51D65EE4A007A923C /* AddressBookController1.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2291AAB31D65EE4A007A923C /* AddressBookController1.xib */; }; 12 | 2291AAB91D65EE57007A923C /* AddressBookController2.m in Sources */ = {isa = PBXBuildFile; fileRef = 2291AAB71D65EE57007A923C /* AddressBookController2.m */; }; 13 | 2291AABA1D65EE57007A923C /* AddressBookController2.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2291AAB81D65EE57007A923C /* AddressBookController2.xib */; }; 14 | 22BEDC131D64ADD900A72128 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC121D64ADD900A72128 /* main.m */; }; 15 | 22BEDC161D64ADD900A72128 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC151D64ADD900A72128 /* AppDelegate.m */; }; 16 | 22BEDC191D64ADD900A72128 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC181D64ADD900A72128 /* ViewController.m */; }; 17 | 22BEDC1E1D64ADD900A72128 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 22BEDC1D1D64ADD900A72128 /* Assets.xcassets */; }; 18 | 22BEDC211D64ADD900A72128 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 22BEDC1F1D64ADD900A72128 /* LaunchScreen.storyboard */; }; 19 | 22BEDC2C1D64ADD900A72128 /* PPGetAddressBookTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC2B1D64ADD900A72128 /* PPGetAddressBookTests.m */; }; 20 | 22BEDC3D1D64AE0E00A72128 /* PPAddressBookHandle.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC381D64AE0E00A72128 /* PPAddressBookHandle.m */; }; 21 | 22BEDC3E1D64AE0E00A72128 /* PPGetAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC3A1D64AE0E00A72128 /* PPGetAddressBook.m */; }; 22 | 22BEDC3F1D64AE0E00A72128 /* PPPersonModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BEDC3C1D64AE0E00A72128 /* PPPersonModel.m */; }; 23 | 22BEDC411D64AE2600A72128 /* defult.png in Resources */ = {isa = PBXBuildFile; fileRef = 22BEDC401D64AE2600A72128 /* defult.png */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 22BEDC281D64ADD900A72128 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 22BEDC061D64ADD900A72128 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 22BEDC0D1D64ADD900A72128; 32 | remoteInfo = PPGetAddressBook; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 2291AAB11D65EE4A007A923C /* AddressBookController1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddressBookController1.h; sourceTree = ""; }; 38 | 2291AAB21D65EE4A007A923C /* AddressBookController1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddressBookController1.m; sourceTree = ""; }; 39 | 2291AAB31D65EE4A007A923C /* AddressBookController1.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AddressBookController1.xib; sourceTree = ""; }; 40 | 2291AAB61D65EE57007A923C /* AddressBookController2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddressBookController2.h; sourceTree = ""; }; 41 | 2291AAB71D65EE57007A923C /* AddressBookController2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddressBookController2.m; sourceTree = ""; }; 42 | 2291AAB81D65EE57007A923C /* AddressBookController2.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AddressBookController2.xib; sourceTree = ""; }; 43 | 22BEDC0E1D64ADD900A72128 /* PPGetAddressBook.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PPGetAddressBook.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 22BEDC121D64ADD900A72128 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 45 | 22BEDC141D64ADD900A72128 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 46 | 22BEDC151D64ADD900A72128 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 47 | 22BEDC171D64ADD900A72128 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 48 | 22BEDC181D64ADD900A72128 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 49 | 22BEDC1D1D64ADD900A72128 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 22BEDC201D64ADD900A72128 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 22BEDC221D64ADD900A72128 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 22BEDC271D64ADD900A72128 /* PPGetAddressBookTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PPGetAddressBookTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 22BEDC2B1D64ADD900A72128 /* PPGetAddressBookTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PPGetAddressBookTests.m; sourceTree = ""; }; 54 | 22BEDC2D1D64ADD900A72128 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 22BEDC371D64AE0E00A72128 /* PPAddressBookHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPAddressBookHandle.h; sourceTree = ""; }; 56 | 22BEDC381D64AE0E00A72128 /* PPAddressBookHandle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPAddressBookHandle.m; sourceTree = ""; }; 57 | 22BEDC391D64AE0E00A72128 /* PPGetAddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPGetAddressBook.h; sourceTree = ""; }; 58 | 22BEDC3A1D64AE0E00A72128 /* PPGetAddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPGetAddressBook.m; sourceTree = ""; }; 59 | 22BEDC3B1D64AE0E00A72128 /* PPPersonModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPersonModel.h; sourceTree = ""; }; 60 | 22BEDC3C1D64AE0E00A72128 /* PPPersonModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPersonModel.m; sourceTree = ""; }; 61 | 22BEDC401D64AE2600A72128 /* defult.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = defult.png; sourceTree = ""; }; 62 | 22EC545B1DA91A1F00485F95 /* PPSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSingleton.h; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 22BEDC0B1D64ADD900A72128 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 22BEDC241D64ADD900A72128 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 2291AAAF1D65EE0A007A923C /* 原始顺序 */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 2291AAB61D65EE57007A923C /* AddressBookController2.h */, 87 | 2291AAB71D65EE57007A923C /* AddressBookController2.m */, 88 | 2291AAB81D65EE57007A923C /* AddressBookController2.xib */, 89 | ); 90 | name = "原始顺序"; 91 | sourceTree = ""; 92 | }; 93 | 2291AAB01D65EE27007A923C /* A~Z顺序排列 */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 2291AAB11D65EE4A007A923C /* AddressBookController1.h */, 97 | 2291AAB21D65EE4A007A923C /* AddressBookController1.m */, 98 | 2291AAB31D65EE4A007A923C /* AddressBookController1.xib */, 99 | ); 100 | name = "A~Z顺序排列"; 101 | sourceTree = ""; 102 | }; 103 | 22BEDC051D64ADD900A72128 = { 104 | isa = PBXGroup; 105 | children = ( 106 | 22BEDC101D64ADD900A72128 /* PPGetAddressBook */, 107 | 22BEDC2A1D64ADD900A72128 /* PPGetAddressBookTests */, 108 | 22BEDC0F1D64ADD900A72128 /* Products */, 109 | ); 110 | sourceTree = ""; 111 | }; 112 | 22BEDC0F1D64ADD900A72128 /* Products */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 22BEDC0E1D64ADD900A72128 /* PPGetAddressBook.app */, 116 | 22BEDC271D64ADD900A72128 /* PPGetAddressBookTests.xctest */, 117 | ); 118 | name = Products; 119 | sourceTree = ""; 120 | }; 121 | 22BEDC101D64ADD900A72128 /* PPGetAddressBook */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 22BEDC361D64AE0E00A72128 /* PPGetAddressBook */, 125 | 22BEDC141D64ADD900A72128 /* AppDelegate.h */, 126 | 22BEDC151D64ADD900A72128 /* AppDelegate.m */, 127 | 22BEDC171D64ADD900A72128 /* ViewController.h */, 128 | 22BEDC181D64ADD900A72128 /* ViewController.m */, 129 | 2291AAB01D65EE27007A923C /* A~Z顺序排列 */, 130 | 2291AAAF1D65EE0A007A923C /* 原始顺序 */, 131 | 22BEDC111D64ADD900A72128 /* Supporting Files */, 132 | ); 133 | path = PPGetAddressBook; 134 | sourceTree = ""; 135 | }; 136 | 22BEDC111D64ADD900A72128 /* Supporting Files */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 22BEDC1D1D64ADD900A72128 /* Assets.xcassets */, 140 | 22BEDC1F1D64ADD900A72128 /* LaunchScreen.storyboard */, 141 | 22BEDC221D64ADD900A72128 /* Info.plist */, 142 | 22BEDC401D64AE2600A72128 /* defult.png */, 143 | 22BEDC121D64ADD900A72128 /* main.m */, 144 | ); 145 | name = "Supporting Files"; 146 | sourceTree = ""; 147 | }; 148 | 22BEDC2A1D64ADD900A72128 /* PPGetAddressBookTests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 22BEDC2B1D64ADD900A72128 /* PPGetAddressBookTests.m */, 152 | 22BEDC2D1D64ADD900A72128 /* Info.plist */, 153 | ); 154 | path = PPGetAddressBookTests; 155 | sourceTree = ""; 156 | }; 157 | 22BEDC361D64AE0E00A72128 /* PPGetAddressBook */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 22EC545B1DA91A1F00485F95 /* PPSingleton.h */, 161 | 22BEDC391D64AE0E00A72128 /* PPGetAddressBook.h */, 162 | 22BEDC3A1D64AE0E00A72128 /* PPGetAddressBook.m */, 163 | 22BEDC371D64AE0E00A72128 /* PPAddressBookHandle.h */, 164 | 22BEDC381D64AE0E00A72128 /* PPAddressBookHandle.m */, 165 | 22BEDC3B1D64AE0E00A72128 /* PPPersonModel.h */, 166 | 22BEDC3C1D64AE0E00A72128 /* PPPersonModel.m */, 167 | ); 168 | path = PPGetAddressBook; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 22BEDC0D1D64ADD900A72128 /* PPGetAddressBook */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 22BEDC301D64ADD900A72128 /* Build configuration list for PBXNativeTarget "PPGetAddressBook" */; 177 | buildPhases = ( 178 | 22BEDC0A1D64ADD900A72128 /* Sources */, 179 | 22BEDC0B1D64ADD900A72128 /* Frameworks */, 180 | 22BEDC0C1D64ADD900A72128 /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = PPGetAddressBook; 187 | productName = PPGetAddressBook; 188 | productReference = 22BEDC0E1D64ADD900A72128 /* PPGetAddressBook.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | 22BEDC261D64ADD900A72128 /* PPGetAddressBookTests */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 22BEDC331D64ADD900A72128 /* Build configuration list for PBXNativeTarget "PPGetAddressBookTests" */; 194 | buildPhases = ( 195 | 22BEDC231D64ADD900A72128 /* Sources */, 196 | 22BEDC241D64ADD900A72128 /* Frameworks */, 197 | 22BEDC251D64ADD900A72128 /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | 22BEDC291D64ADD900A72128 /* PBXTargetDependency */, 203 | ); 204 | name = PPGetAddressBookTests; 205 | productName = PPGetAddressBookTests; 206 | productReference = 22BEDC271D64ADD900A72128 /* PPGetAddressBookTests.xctest */; 207 | productType = "com.apple.product-type.bundle.unit-test"; 208 | }; 209 | /* End PBXNativeTarget section */ 210 | 211 | /* Begin PBXProject section */ 212 | 22BEDC061D64ADD900A72128 /* Project object */ = { 213 | isa = PBXProject; 214 | attributes = { 215 | LastUpgradeCheck = 0730; 216 | ORGANIZATIONNAME = AndyPang; 217 | TargetAttributes = { 218 | 22BEDC0D1D64ADD900A72128 = { 219 | CreatedOnToolsVersion = 7.3.1; 220 | DevelopmentTeam = K6769CKV8N; 221 | }; 222 | 22BEDC261D64ADD900A72128 = { 223 | CreatedOnToolsVersion = 7.3.1; 224 | TestTargetID = 22BEDC0D1D64ADD900A72128; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = 22BEDC091D64ADD900A72128 /* Build configuration list for PBXProject "PPGetAddressBook" */; 229 | compatibilityVersion = "Xcode 3.2"; 230 | developmentRegion = English; 231 | hasScannedForEncodings = 0; 232 | knownRegions = ( 233 | en, 234 | Base, 235 | ); 236 | mainGroup = 22BEDC051D64ADD900A72128; 237 | productRefGroup = 22BEDC0F1D64ADD900A72128 /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | 22BEDC0D1D64ADD900A72128 /* PPGetAddressBook */, 242 | 22BEDC261D64ADD900A72128 /* PPGetAddressBookTests */, 243 | ); 244 | }; 245 | /* End PBXProject section */ 246 | 247 | /* Begin PBXResourcesBuildPhase section */ 248 | 22BEDC0C1D64ADD900A72128 /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 22BEDC211D64ADD900A72128 /* LaunchScreen.storyboard in Resources */, 253 | 2291AAB51D65EE4A007A923C /* AddressBookController1.xib in Resources */, 254 | 22BEDC411D64AE2600A72128 /* defult.png in Resources */, 255 | 2291AABA1D65EE57007A923C /* AddressBookController2.xib in Resources */, 256 | 22BEDC1E1D64ADD900A72128 /* Assets.xcassets in Resources */, 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | 22BEDC251D64ADD900A72128 /* Resources */ = { 261 | isa = PBXResourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXResourcesBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | 22BEDC0A1D64ADD900A72128 /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | 22BEDC3F1D64AE0E00A72128 /* PPPersonModel.m in Sources */, 275 | 22BEDC191D64ADD900A72128 /* ViewController.m in Sources */, 276 | 2291AAB91D65EE57007A923C /* AddressBookController2.m in Sources */, 277 | 22BEDC161D64ADD900A72128 /* AppDelegate.m in Sources */, 278 | 22BEDC131D64ADD900A72128 /* main.m in Sources */, 279 | 22BEDC3D1D64AE0E00A72128 /* PPAddressBookHandle.m in Sources */, 280 | 2291AAB41D65EE4A007A923C /* AddressBookController1.m in Sources */, 281 | 22BEDC3E1D64AE0E00A72128 /* PPGetAddressBook.m in Sources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | 22BEDC231D64ADD900A72128 /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 22BEDC2C1D64ADD900A72128 /* PPGetAddressBookTests.m in Sources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | /* End PBXSourcesBuildPhase section */ 294 | 295 | /* Begin PBXTargetDependency section */ 296 | 22BEDC291D64ADD900A72128 /* PBXTargetDependency */ = { 297 | isa = PBXTargetDependency; 298 | target = 22BEDC0D1D64ADD900A72128 /* PPGetAddressBook */; 299 | targetProxy = 22BEDC281D64ADD900A72128 /* PBXContainerItemProxy */; 300 | }; 301 | /* End PBXTargetDependency section */ 302 | 303 | /* Begin PBXVariantGroup section */ 304 | 22BEDC1F1D64ADD900A72128 /* LaunchScreen.storyboard */ = { 305 | isa = PBXVariantGroup; 306 | children = ( 307 | 22BEDC201D64ADD900A72128 /* Base */, 308 | ); 309 | name = LaunchScreen.storyboard; 310 | sourceTree = ""; 311 | }; 312 | /* End PBXVariantGroup section */ 313 | 314 | /* Begin XCBuildConfiguration section */ 315 | 22BEDC2E1D64ADD900A72128 /* Debug */ = { 316 | isa = XCBuildConfiguration; 317 | buildSettings = { 318 | ALWAYS_SEARCH_USER_PATHS = NO; 319 | CLANG_ANALYZER_NONNULL = YES; 320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 321 | CLANG_CXX_LIBRARY = "libc++"; 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_ENABLE_OBJC_ARC = YES; 324 | CLANG_WARN_BOOL_CONVERSION = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 327 | CLANG_WARN_EMPTY_BODY = YES; 328 | CLANG_WARN_ENUM_CONVERSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | DEBUG_INFORMATION_FORMAT = dwarf; 336 | ENABLE_STRICT_OBJC_MSGSEND = YES; 337 | ENABLE_TESTABILITY = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_DYNAMIC_NO_PIC = NO; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_OPTIMIZATION_LEVEL = 0; 342 | GCC_PREPROCESSOR_DEFINITIONS = ( 343 | "DEBUG=1", 344 | "$(inherited)", 345 | ); 346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 347 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 348 | GCC_WARN_UNDECLARED_SELECTOR = YES; 349 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 350 | GCC_WARN_UNUSED_FUNCTION = YES; 351 | GCC_WARN_UNUSED_VARIABLE = YES; 352 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 353 | MTL_ENABLE_DEBUG_INFO = YES; 354 | ONLY_ACTIVE_ARCH = YES; 355 | SDKROOT = iphoneos; 356 | TARGETED_DEVICE_FAMILY = "1,2"; 357 | }; 358 | name = Debug; 359 | }; 360 | 22BEDC2F1D64ADD900A72128 /* Release */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | ALWAYS_SEARCH_USER_PATHS = NO; 364 | CLANG_ANALYZER_NONNULL = YES; 365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 366 | CLANG_CXX_LIBRARY = "libc++"; 367 | CLANG_ENABLE_MODULES = YES; 368 | CLANG_ENABLE_OBJC_ARC = YES; 369 | CLANG_WARN_BOOL_CONVERSION = YES; 370 | CLANG_WARN_CONSTANT_CONVERSION = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INT_CONVERSION = YES; 375 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 376 | CLANG_WARN_UNREACHABLE_CODE = YES; 377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 378 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 379 | COPY_PHASE_STRIP = NO; 380 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 381 | ENABLE_NS_ASSERTIONS = NO; 382 | ENABLE_STRICT_OBJC_MSGSEND = YES; 383 | GCC_C_LANGUAGE_STANDARD = gnu99; 384 | GCC_NO_COMMON_BLOCKS = YES; 385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 386 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 387 | GCC_WARN_UNDECLARED_SELECTOR = YES; 388 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 389 | GCC_WARN_UNUSED_FUNCTION = YES; 390 | GCC_WARN_UNUSED_VARIABLE = YES; 391 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 392 | MTL_ENABLE_DEBUG_INFO = NO; 393 | SDKROOT = iphoneos; 394 | TARGETED_DEVICE_FAMILY = "1,2"; 395 | VALIDATE_PRODUCT = YES; 396 | }; 397 | name = Release; 398 | }; 399 | 22BEDC311D64ADD900A72128 /* Debug */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 403 | CODE_SIGN_IDENTITY = "iPhone Developer"; 404 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 405 | INFOPLIST_FILE = PPGetAddressBook/Info.plist; 406 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 407 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 408 | PRODUCT_BUNDLE_IDENTIFIER = com.jkpang.PPGetAddressBook; 409 | PRODUCT_NAME = "$(TARGET_NAME)"; 410 | PROVISIONING_PROFILE = ""; 411 | }; 412 | name = Debug; 413 | }; 414 | 22BEDC321D64ADD900A72128 /* Release */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 418 | CODE_SIGN_IDENTITY = "iPhone Developer"; 419 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 420 | INFOPLIST_FILE = PPGetAddressBook/Info.plist; 421 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 422 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 423 | PRODUCT_BUNDLE_IDENTIFIER = com.jkpang.PPGetAddressBook; 424 | PRODUCT_NAME = "$(TARGET_NAME)"; 425 | PROVISIONING_PROFILE = ""; 426 | }; 427 | name = Release; 428 | }; 429 | 22BEDC341D64ADD900A72128 /* Debug */ = { 430 | isa = XCBuildConfiguration; 431 | buildSettings = { 432 | BUNDLE_LOADER = "$(TEST_HOST)"; 433 | INFOPLIST_FILE = PPGetAddressBookTests/Info.plist; 434 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 435 | PRODUCT_BUNDLE_IDENTIFIER = com.jkpang.PPGetAddressBookTests; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PPGetAddressBook.app/PPGetAddressBook"; 438 | }; 439 | name = Debug; 440 | }; 441 | 22BEDC351D64ADD900A72128 /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | BUNDLE_LOADER = "$(TEST_HOST)"; 445 | INFOPLIST_FILE = PPGetAddressBookTests/Info.plist; 446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 447 | PRODUCT_BUNDLE_IDENTIFIER = com.jkpang.PPGetAddressBookTests; 448 | PRODUCT_NAME = "$(TARGET_NAME)"; 449 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PPGetAddressBook.app/PPGetAddressBook"; 450 | }; 451 | name = Release; 452 | }; 453 | /* End XCBuildConfiguration section */ 454 | 455 | /* Begin XCConfigurationList section */ 456 | 22BEDC091D64ADD900A72128 /* Build configuration list for PBXProject "PPGetAddressBook" */ = { 457 | isa = XCConfigurationList; 458 | buildConfigurations = ( 459 | 22BEDC2E1D64ADD900A72128 /* Debug */, 460 | 22BEDC2F1D64ADD900A72128 /* Release */, 461 | ); 462 | defaultConfigurationIsVisible = 0; 463 | defaultConfigurationName = Release; 464 | }; 465 | 22BEDC301D64ADD900A72128 /* Build configuration list for PBXNativeTarget "PPGetAddressBook" */ = { 466 | isa = XCConfigurationList; 467 | buildConfigurations = ( 468 | 22BEDC311D64ADD900A72128 /* Debug */, 469 | 22BEDC321D64ADD900A72128 /* Release */, 470 | ); 471 | defaultConfigurationIsVisible = 0; 472 | defaultConfigurationName = Release; 473 | }; 474 | 22BEDC331D64ADD900A72128 /* Build configuration list for PBXNativeTarget "PPGetAddressBookTests" */ = { 475 | isa = XCConfigurationList; 476 | buildConfigurations = ( 477 | 22BEDC341D64ADD900A72128 /* Debug */, 478 | 22BEDC351D64ADD900A72128 /* Release */, 479 | ); 480 | defaultConfigurationIsVisible = 0; 481 | defaultConfigurationName = Release; 482 | }; 483 | /* End XCConfigurationList section */ 484 | }; 485 | rootObject = 22BEDC061D64ADD900A72128 /* Project object */; 486 | } 487 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/AndyPang.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/AndyPang.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/duoyi.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/duoyi.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/huangqisheng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/PPGetAddressBook.xcodeproj/project.xcworkspace/xcuserdata/huangqisheng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/AndyPang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/AndyPang.xcuserdatad/xcschemes/PPGetAddressBook.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/AndyPang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PPGetAddressBook.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 22BEDC0D1D64ADD900A72128 16 | 17 | primary 18 | 19 | 20 | 22BEDC261D64ADD900A72128 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/duoyi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/duoyi.xcuserdatad/xcschemes/PPGetAddressBook.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/duoyi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PPGetAddressBook.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 22BEDC0D1D64ADD900A72128 16 | 17 | primary 18 | 19 | 20 | 22BEDC261D64ADD900A72128 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/huangqisheng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/huangqisheng.xcuserdatad/xcschemes/PPGetAddressBook.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PPGetAddressBook.xcodeproj/xcuserdata/huangqisheng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PPGetAddressBook.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 22BEDC0D1D64ADD900A72128 16 | 17 | primary 18 | 19 | 20 | 22BEDC261D64ADD900A72128 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController1.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookController1.h 3 | // PPGetAddressBook 4 | // 5 | // Created by 黄祺升 on 16/8/18. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AddressBookController1 : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController1.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookController1.m 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "AddressBookController1.h" 10 | #import "PPGetAddressBook.h" 11 | #define START NSDate *startTime = [NSDate date] 12 | #define END NSLog(@"Time: %f", -[startTime timeIntervalSinceNow]) 13 | 14 | @interface AddressBookController1 () 15 | 16 | @property (nonatomic, copy) NSDictionary *contactPeopleDict; 17 | @property (nonatomic, copy) NSArray *keys; 18 | 19 | @end 20 | 21 | @implementation AddressBookController1 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | 27 | self.navigationItem.title = @"A~Z顺序排列"; 28 | 29 | self.tableView.tableFooterView = [UIView new]; 30 | UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 31 | indicator.frame = CGRectMake(0, 0, 80, 80); 32 | indicator.center = CGPointMake([UIScreen mainScreen].bounds.size.width*0.5, [UIScreen mainScreen].bounds.size.height*0.5-80); 33 | indicator.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.700]; 34 | indicator.clipsToBounds = YES; 35 | indicator.layer.cornerRadius = 6; 36 | [indicator startAnimating]; 37 | [self.view addSubview:indicator]; 38 | 39 | 40 | //获取按联系人姓名首字拼音A~Z排序(已经对姓名的第二个字做了处理) 41 | [PPGetAddressBook getOrderAddressBook:^(NSDictionary *addressBookDict, NSArray *nameKeys) { 42 | 43 | [indicator stopAnimating]; 44 | 45 | //装着所有联系人的字典 46 | self.contactPeopleDict = addressBookDict; 47 | //联系人分组按拼音分组的Key值 48 | self.keys = nameKeys; 49 | 50 | [self.tableView reloadData]; 51 | } authorizationFailure:^{ 52 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" 53 | message:@"请在iPhone的“设置-隐私-通讯录”选项中,允许PPAddressBook访问您的通讯录" 54 | delegate:nil 55 | cancelButtonTitle:@"知道了" 56 | otherButtonTitles:nil]; 57 | [alert show]; 58 | }]; 59 | 60 | self.tableView.rowHeight = 60; 61 | } 62 | 63 | #pragma mark - TableViewDatasouce/TableViewDelegate 64 | 65 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 66 | { 67 | return _keys.count; 68 | } 69 | 70 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 71 | { 72 | NSString *key = _keys[section]; 73 | return [_contactPeopleDict[key] count]; 74 | } 75 | 76 | - (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 77 | { 78 | return _keys[section]; 79 | } 80 | 81 | //右侧的索引 82 | - (NSArray*)sectionIndexTitlesForTableView:(UITableView *)tableView 83 | { 84 | return _keys; 85 | } 86 | 87 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 88 | { 89 | static NSString *reuseIdentifier = @"cell"; 90 | 91 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; 92 | if (!cell) 93 | { 94 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 95 | } 96 | 97 | NSString *key = _keys[indexPath.section]; 98 | PPPersonModel *people = [_contactPeopleDict[key] objectAtIndex:indexPath.row]; 99 | 100 | cell.imageView.image = people.headerImage ? people.headerImage : [UIImage imageNamed:@"defult"]; 101 | cell.imageView.layer.cornerRadius = 60/2; 102 | cell.imageView.clipsToBounds = YES; 103 | cell.textLabel.text = people.name; 104 | 105 | return cell; 106 | } 107 | 108 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 109 | { 110 | NSString *key = _keys[indexPath.section]; 111 | PPPersonModel *people = [_contactPeopleDict[key] objectAtIndex:indexPath.row]; 112 | 113 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:people.name 114 | message:[NSString stringWithFormat:@"号码:%@",people.mobileArray] 115 | delegate:nil 116 | cancelButtonTitle:@"知道啦" 117 | otherButtonTitles:nil]; 118 | [alert show]; 119 | } 120 | 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController1.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController2.h: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookController2.h 3 | // PPGetAddressBook 4 | // 5 | // Created by 黄祺升 on 16/8/18. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AddressBookController2 : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController2.m: -------------------------------------------------------------------------------- 1 | // 2 | // AddressBookController2.m 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "AddressBookController2.h" 10 | #import "PPGetAddressBook.h" 11 | 12 | @interface AddressBookController2 () 13 | 14 | @property (nonatomic, copy) NSArray *dataSource; 15 | 16 | @end 17 | 18 | @implementation AddressBookController2 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | self.navigationItem.title = @"原始顺序"; 24 | 25 | self.tableView.tableFooterView = [UIView new]; 26 | UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 27 | indicator.frame = CGRectMake(0, 0, 80, 80); 28 | indicator.center = CGPointMake([UIScreen mainScreen].bounds.size.width*0.5, [UIScreen mainScreen].bounds.size.height*0.5-80); 29 | indicator.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.700]; 30 | indicator.clipsToBounds = YES; 31 | indicator.layer.cornerRadius = 6; 32 | [indicator startAnimating]; 33 | [self.view addSubview:indicator]; 34 | 35 | //获取没有经过排序的联系人模型 36 | [PPGetAddressBook getOriginalAddressBook:^(NSArray *addressBookArray) { 37 | [indicator stopAnimating]; 38 | 39 | _dataSource = addressBookArray; 40 | [self.tableView reloadData]; 41 | 42 | } authorizationFailure:^{ 43 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" 44 | message:@"请在iPhone的“设置-隐私-通讯录”选项中,允许PPAddressBook访问您的通讯录" 45 | delegate:nil 46 | cancelButtonTitle:@"知道了" 47 | otherButtonTitles:nil]; 48 | [alert show]; 49 | }]; 50 | 51 | self.tableView.rowHeight = 60; 52 | } 53 | 54 | 55 | #pragma mark - TableViewDatasouce/TableViewDelegate 56 | 57 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 58 | 59 | return _dataSource.count; 60 | } 61 | 62 | 63 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 64 | 65 | static NSString *reuseIdentifier = @"cell"; 66 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; 67 | if (!cell) 68 | { 69 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 70 | } 71 | PPPersonModel *people = _dataSource[indexPath.row]; 72 | cell.imageView.image = people.headerImage ? people.headerImage : [UIImage imageNamed:@"defult"]; 73 | cell.imageView.layer.cornerRadius = 60/2; 74 | cell.imageView.clipsToBounds = YES; 75 | cell.textLabel.text = people.name; 76 | 77 | return cell; 78 | } 79 | 80 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 81 | { 82 | PPPersonModel *people = _dataSource[indexPath.row]; 83 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:people.name 84 | message:[NSString stringWithFormat:@"号码:%@",people.mobileArray] 85 | delegate:nil 86 | cancelButtonTitle:@"知道啦" 87 | otherButtonTitles:nil]; 88 | [alert show]; 89 | } 90 | 91 | 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /PPGetAddressBook/AddressBookController2.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /PPGetAddressBook/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /PPGetAddressBook/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | #import "PPGetAddressBook.h" 12 | 13 | @interface AppDelegate () 14 | 15 | @end 16 | 17 | @implementation AppDelegate 18 | 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 21 | // Override point for customization after application launch. 22 | 23 | //请求用户获取通讯录权限 24 | [PPGetAddressBook requestAddressBookAuthorization]; 25 | 26 | ViewController *mainVC = [ViewController new]; 27 | UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:mainVC]; 28 | self.window.rootViewController = navi; 29 | 30 | return YES; 31 | } 32 | 33 | - (void)applicationWillResignActive:(UIApplication *)application { 34 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 35 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 36 | } 37 | 38 | - (void)applicationDidEnterBackground:(UIApplication *)application { 39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | - (void)applicationWillEnterForeground:(UIApplication *)application { 44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application { 48 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | } 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /PPGetAddressBook/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /PPGetAddressBook/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /PPGetAddressBook/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSContactsUsageDescription 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | LaunchScreen 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPAddressBookHandle.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPDataHandle.h 3 | // PPAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | /* 10 | ********************************************************************************* 11 | * 12 | *⭐️⭐️⭐️ 新建 PP-iOS学习交流群: 323408051 欢迎加入!!! ⭐️⭐️⭐️ 13 | * 14 | * 如果您在使用 PPGetAddressBook 的过程中出现bug或有更好的建议,还请及时以下列方式联系我,我会及 15 | * 时修复bug,解决问题. 16 | * 17 | * Weibo : jkpang-庞 18 | * Email : jkpang@outlook.com 19 | * QQ 群 : 323408051 20 | * GitHub: https://github.com/jkpang 21 | * 22 | * PS:我的另外两个很好用的封装,欢迎使用! 23 | * 1.对AFNetworking 3.x 与YYCache的二次封装,一句代码搞定数据请求与缓存,告别FMDB: 24 | * GitHub:https://github.com/jkpang/PPNetworkHelper 25 | * 2.仿京东淘宝商品数量的加减按钮,可定制程度高,使用简单: 26 | * GitHub:https://github.com/jkpang/PPNumberButton 27 | * 28 | * 如果 PPGetAddressBook 好用,希望您能Star支持,你的 ⭐️ 是我持续更新的动力! 29 | ********************************************************************************* 30 | */ 31 | 32 | #import 33 | 34 | #ifdef __IPHONE_9_0 35 | #import 36 | #endif 37 | #import 38 | 39 | #import "PPPersonModel.h" 40 | #import "PPSingleton.h" 41 | 42 | #define IOS9_LATER ([[UIDevice currentDevice] systemVersion].floatValue > 9.0 ? YES : NO ) 43 | 44 | /** 一个联系人的相关信息*/ 45 | typedef void(^PPPersonModelBlock)(PPPersonModel *model); 46 | /** 授权失败的Block*/ 47 | typedef void(^AuthorizationFailure)(void); 48 | 49 | 50 | 51 | @interface PPAddressBookHandle : NSObject 52 | 53 | PPSingletonH(AddressBookHandle) 54 | 55 | 56 | /** 57 | 请求用户通讯录授权 58 | 59 | @param success 授权成功的回调 60 | */ 61 | - (void)requestAuthorizationWithSuccessBlock:(void(^)(void))success; 62 | 63 | /** 64 | * 返回每个联系人的模型 65 | * 66 | * @param personModel 单个联系人模型 67 | * @param failure 授权失败的Block 68 | */ 69 | - (void)getAddressBookDataSource:(PPPersonModelBlock)personModel authorizationFailure:(AuthorizationFailure)failure; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPAddressBookHandle.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPDataHandle.m 3 | // PPAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "PPAddressBookHandle.h" 10 | 11 | 12 | @interface PPAddressBookHandle () 13 | 14 | #ifdef __IPHONE_9_0 15 | /** iOS9之后的通讯录对象*/ 16 | @property (nonatomic, strong) CNContactStore *contactStore; 17 | #endif 18 | 19 | @end 20 | 21 | @implementation PPAddressBookHandle 22 | 23 | PPSingletonM(AddressBookHandle) 24 | 25 | - (void)requestAuthorizationWithSuccessBlock:(void (^)(void))success 26 | { 27 | if(IOS9_LATER) 28 | { 29 | #ifdef __IPHONE_9_0 30 | // 1.判断是否授权成功,若授权成功直接return 31 | if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) return; 32 | // 2.创建通讯录 33 | //CNContactStore *store = [[CNContactStore alloc] init]; 34 | // 3.授权 35 | [self.contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { 36 | if (granted) { 37 | NSLog(@"授权成功"); success(); 38 | }else{ 39 | NSLog(@"授权失败"); 40 | } 41 | }]; 42 | #endif 43 | } 44 | else 45 | { 46 | // 1.获取授权的状态 47 | ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); 48 | // 2.判断授权状态,如果是未决定状态,才需要请求 49 | if (status == kABAuthorizationStatusNotDetermined) { 50 | // 3.创建通讯录进行授权 51 | ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); 52 | ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 53 | if (granted) { 54 | NSLog(@"授权成功"); success(); 55 | } else { 56 | NSLog(@"授权失败"); 57 | } 58 | 59 | }); 60 | } 61 | 62 | } 63 | 64 | } 65 | 66 | 67 | - (void)getAddressBookDataSource:(PPPersonModelBlock)personModel authorizationFailure:(AuthorizationFailure)failure 68 | { 69 | 70 | if(IOS9_LATER) 71 | { 72 | [self getDataSourceFrom_IOS9_Later:personModel authorizationFailure:failure]; 73 | } 74 | else 75 | { 76 | [self getDataSourceFrom_IOS9_Ago:personModel authorizationFailure:failure]; 77 | } 78 | 79 | } 80 | 81 | #pragma mark - IOS9之前获取通讯录的方法 82 | - (void)getDataSourceFrom_IOS9_Ago:(PPPersonModelBlock)personModel authorizationFailure:(AuthorizationFailure)failure 83 | { 84 | // 1.获取授权状态 85 | ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); 86 | 87 | // 2.如果没有授权,先执行授权失败的block后return 88 | if (status != kABAuthorizationStatusAuthorized/** 已经授权*/) 89 | { 90 | failure ? failure() : nil; 91 | return; 92 | } 93 | 94 | // 3.创建通信录对象 95 | ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); 96 | 97 | //4.按照排序规则从通信录对象中请求所有的联系人,并按姓名属性中的姓(LastName)来排序 98 | ABRecordRef recordRef = ABAddressBookCopyDefaultSource(addressBook); 99 | CFArrayRef allPeopleArray = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, recordRef, kABPersonSortByLastName); 100 | 101 | // 5.遍历每个联系人的信息,并装入模型 102 | for(id personInfo in (__bridge NSArray *)allPeopleArray) 103 | { 104 | PPPersonModel *model = [PPPersonModel new]; 105 | 106 | // 5.1获取到联系人 107 | ABRecordRef person = (__bridge ABRecordRef)(personInfo); 108 | 109 | // 5.2获取全名 110 | NSString *name = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person); 111 | model.name = name.length > 0 ? name : @"无名氏" ; 112 | 113 | // 5.3获取头像数据 114 | NSData *imageData = (__bridge_transfer NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail); 115 | model.headerImage = [UIImage imageWithData:imageData]; 116 | 117 | // 5.4获取每个人所有的电话号码 118 | ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty); 119 | 120 | CFIndex phoneCount = ABMultiValueGetCount(phones); 121 | for (CFIndex i = 0; i < phoneCount; i++) 122 | { 123 | // 号码 124 | NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, i); 125 | NSString *mobile = [self removeSpecialSubString:phoneValue]; 126 | 127 | [model.mobileArray addObject: mobile ? mobile : @"空号"]; 128 | 129 | } 130 | // 5.5将联系人模型回调出去 131 | personModel ? personModel(model) : nil; 132 | 133 | CFRelease(phones); 134 | } 135 | 136 | // 释放不再使用的对象 137 | CFRelease(allPeopleArray); 138 | CFRelease(recordRef); 139 | CFRelease(addressBook); 140 | 141 | } 142 | 143 | #pragma mark - IOS9之后获取通讯录的方法 144 | - (void)getDataSourceFrom_IOS9_Later:(PPPersonModelBlock)personModel authorizationFailure:(AuthorizationFailure)failure 145 | { 146 | #ifdef __IPHONE_9_0 147 | // 1.获取授权状态 148 | CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; 149 | // 2.如果没有授权,先执行授权失败的block后return 150 | if (status != CNAuthorizationStatusAuthorized) 151 | { 152 | failure ? failure() : nil; 153 | return; 154 | } 155 | // 3.获取联系人 156 | // 3.1.创建联系人仓库 157 | //CNContactStore *store = [[CNContactStore alloc] init]; 158 | 159 | // 3.2.创建联系人的请求对象 160 | // keys决定能获取联系人哪些信息,例:姓名,电话,头像等 161 | NSArray *fetchKeys = @[[CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName],CNContactPhoneNumbersKey,CNContactThumbnailImageDataKey]; 162 | CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:fetchKeys]; 163 | 164 | // 3.3.请求联系人 165 | [self.contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact,BOOL * _Nonnull stop) { 166 | 167 | // 获取联系人全名 168 | NSString *name = [CNContactFormatter stringFromContact:contact style:CNContactFormatterStyleFullName]; 169 | 170 | // 创建联系人模型 171 | PPPersonModel *model = [PPPersonModel new]; 172 | model.name = name.length > 0 ? name : @"无名氏" ; 173 | 174 | // 联系人头像 175 | model.headerImage = [UIImage imageWithData:contact.thumbnailImageData]; 176 | 177 | // 获取一个人的所有电话号码 178 | NSArray *phones = contact.phoneNumbers; 179 | 180 | for (CNLabeledValue *labelValue in phones) 181 | { 182 | CNPhoneNumber *phoneNumber = labelValue.value; 183 | NSString *mobile = [self removeSpecialSubString:phoneNumber.stringValue]; 184 | [model.mobileArray addObject: mobile ? mobile : @"空号"]; 185 | } 186 | 187 | //将联系人模型回调出去 188 | personModel ? personModel(model) : nil; 189 | }]; 190 | #endif 191 | 192 | } 193 | 194 | //过滤指定字符串(可自定义添加自己过滤的字符串) 195 | - (NSString *)removeSpecialSubString: (NSString *)string 196 | { 197 | string = [string stringByReplacingOccurrencesOfString:@"+86" withString:@""]; 198 | string = [string stringByReplacingOccurrencesOfString:@"-" withString:@""]; 199 | string = [string stringByReplacingOccurrencesOfString:@"(" withString:@""]; 200 | string = [string stringByReplacingOccurrencesOfString:@")" withString:@""]; 201 | string = [string stringByReplacingOccurrencesOfString:@" " withString:@""]; 202 | string = [string stringByReplacingOccurrencesOfString:@" " withString:@""]; 203 | 204 | return string; 205 | } 206 | 207 | #pragma mark - lazy 208 | 209 | #ifdef __IPHONE_9_0 210 | - (CNContactStore *)contactStore 211 | { 212 | if(!_contactStore) 213 | { 214 | _contactStore = [[CNContactStore alloc] init]; 215 | } 216 | return _contactStore; 217 | } 218 | #endif 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPGetAddressBook.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPGetAddressBook.h 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | /* 10 | ********************************************************************************* 11 | * 12 | *⭐️⭐️⭐️ 新建 PP-iOS学习交流群: 323408051 欢迎加入!!! ⭐️⭐️⭐️ 13 | * 14 | * 如果您在使用 PPGetAddressBook 的过程中出现bug或有更好的建议,还请及时以下列方式联系我,我会及 15 | * 时修复bug,解决问题. 16 | * 17 | * Weibo : jkpang-庞 18 | * Email : jkpang@outlook.com 19 | * QQ 群 : 323408051 20 | * GitHub: https://github.com/jkpang 21 | * 22 | * PS:我的另外两个很好用的封装,欢迎使用! 23 | * 1.对AFNetworking 3.x 与YYCache的二次封装,一句代码搞定数据请求与缓存,告别FMDB: 24 | * GitHub:https://github.com/jkpang/PPNetworkHelper 25 | * 2.仿京东淘宝商品数量的加减按钮,可定制程度高,使用简单: 26 | * GitHub:https://github.com/jkpang/PPNumberButton 27 | * 28 | * 如果 PPGetAddressBook 好用,希望您能Star支持,你的 ⭐️ 是我持续更新的动力! 29 | ********************************************************************************* 30 | */ 31 | 32 | #import 33 | #import "PPAddressBookHandle.h" 34 | #import "PPPersonModel.h" 35 | 36 | /** 37 | * 获取原始顺序的所有联系人的Block 38 | */ 39 | typedef void(^AddressBookArrayBlock)(NSArray *addressBookArray); 40 | 41 | /** 42 | * 获取按A~Z顺序排列的所有联系人的Block 43 | * 44 | * @param addressBookDict 装有所有联系人的字典->每个字典key对应装有多个联系人模型的数组->每个模型里面包含着用户的相关信息. 45 | * @param peopleNameKey 联系人姓名的大写首字母的数组 46 | */ 47 | typedef void(^AddressBookDictBlock)(NSDictionary *addressBookDict,NSArray *nameKeys); 48 | 49 | 50 | 51 | @interface PPGetAddressBook : NSObject 52 | 53 | /** 54 | * 请求用户是否授权APP访问通讯录的权限,建议在APPDeletegate.m中的didFinishLaunchingWithOptions方法中调用 55 | */ 56 | + (void)requestAddressBookAuthorization; 57 | 58 | /** 59 | * 获取原始顺序排列的所有联系人 60 | * 61 | * @param addressBookArray 装着原始顺序的联系人字典Block回调 62 | */ 63 | + (void)getOriginalAddressBook:(AddressBookArrayBlock)addressBookArray authorizationFailure:(AuthorizationFailure)failure; 64 | 65 | /** 66 | * 获取按A~Z顺序排列的所有联系人 67 | * 68 | * @param addressBookInfo 装着A~Z排序的联系人字典Block回调 69 | * @param failure 授权失败的Block 70 | */ 71 | + (void)getOrderAddressBook:(AddressBookDictBlock)addressBookInfo authorizationFailure:(AuthorizationFailure)failure; 72 | 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPGetAddressBook.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPAddressBook.m 3 | // PPAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "PPGetAddressBook.h" 10 | 11 | #define kPPAddressBookHandle [PPAddressBookHandle sharedAddressBookHandle] 12 | 13 | #define START NSDate *startTime = [NSDate date] 14 | #define END NSLog(@"Time: %f", -[startTime timeIntervalSinceNow]) 15 | 16 | @implementation PPGetAddressBook 17 | 18 | + (void)requestAddressBookAuthorization 19 | { 20 | [kPPAddressBookHandle requestAuthorizationWithSuccessBlock:^{ 21 | [self getOrderAddressBook:nil authorizationFailure:nil]; 22 | }]; 23 | } 24 | 25 | + (void)initialize 26 | { 27 | [self getOrderAddressBook:nil authorizationFailure:nil]; 28 | } 29 | 30 | #pragma mark - 获取原始顺序所有联系人 31 | + (void)getOriginalAddressBook:(AddressBookArrayBlock)addressBookArray authorizationFailure:(AuthorizationFailure)failure 32 | { 33 | // 将耗时操作放到子线程 34 | dispatch_queue_t queue = dispatch_queue_create("addressBook.array", DISPATCH_QUEUE_SERIAL); 35 | 36 | dispatch_async(queue, ^{ 37 | 38 | NSMutableArray *array = [NSMutableArray array]; 39 | [kPPAddressBookHandle getAddressBookDataSource:^(PPPersonModel *model) { 40 | 41 | [array addObject:model]; 42 | 43 | } authorizationFailure:^{ 44 | 45 | dispatch_async(dispatch_get_main_queue(), ^{ 46 | failure ? failure() : nil; 47 | }); 48 | }]; 49 | 50 | // 将联系人数组回调到主线程 51 | dispatch_async(dispatch_get_main_queue(), ^{ 52 | addressBookArray ? addressBookArray(array) : nil ; 53 | }); 54 | }); 55 | 56 | } 57 | 58 | #pragma mark - 获取按A~Z顺序排列的所有联系人 59 | + (void)getOrderAddressBook:(AddressBookDictBlock)addressBookInfo authorizationFailure:(AuthorizationFailure)failure 60 | { 61 | 62 | // 将耗时操作放到子线程 63 | dispatch_queue_t queue = dispatch_queue_create("addressBook.infoDict", DISPATCH_QUEUE_SERIAL); 64 | 65 | dispatch_async(queue, ^{ 66 | 67 | NSMutableDictionary *addressBookDict = [NSMutableDictionary dictionary]; 68 | [kPPAddressBookHandle getAddressBookDataSource:^(PPPersonModel *model) { 69 | //获取到姓名的大写首字母 70 | NSString *firstLetterString = [self getFirstLetterFromString:model.name]; 71 | //如果该字母对应的联系人模型不为空,则将此联系人模型添加到此数组中 72 | if (addressBookDict[firstLetterString]) 73 | { 74 | [addressBookDict[firstLetterString] addObject:model]; 75 | } 76 | //没有出现过该首字母,则在字典中新增一组key-value 77 | else 78 | { 79 | //创建新发可变数组存储该首字母对应的联系人模型 80 | NSMutableArray *arrGroupNames = [NSMutableArray arrayWithObject:model]; 81 | 82 | [arrGroupNames addObject:model]; 83 | //将首字母-姓名数组作为key-value加入到字典中 84 | [addressBookDict setObject:arrGroupNames forKey:firstLetterString]; 85 | } 86 | } authorizationFailure:^{ 87 | 88 | dispatch_async(dispatch_get_main_queue(), ^{ 89 | failure ? failure() : nil; 90 | }); 91 | }]; 92 | 93 | // 将addressBookDict字典中的所有Key值进行排序: A~Z 94 | NSArray *nameKeys = [[addressBookDict allKeys] sortedArrayUsingSelector:@selector(compare:)]; 95 | 96 | // 将 "#" 排列在 A~Z 的后面 97 | if ([nameKeys.firstObject isEqualToString:@"#"]) 98 | { 99 | NSMutableArray *mutableNamekeys = [NSMutableArray arrayWithArray:nameKeys]; 100 | [mutableNamekeys insertObject:nameKeys.firstObject atIndex:nameKeys.count]; 101 | [mutableNamekeys removeObjectAtIndex:0]; 102 | 103 | dispatch_async(dispatch_get_main_queue(), ^{ 104 | addressBookInfo ? addressBookInfo(addressBookDict,mutableNamekeys) : nil; 105 | }); 106 | return; 107 | } 108 | 109 | // 将排序好的通讯录数据回调到主线程 110 | dispatch_async(dispatch_get_main_queue(), ^{ 111 | addressBookInfo ? addressBookInfo(addressBookDict,nameKeys) : nil; 112 | }); 113 | 114 | }); 115 | 116 | } 117 | 118 | 119 | #pragma mark - 获取联系人姓名首字母(传入汉字字符串, 返回大写拼音首字母) 120 | + (NSString *)getFirstLetterFromString:(NSString *)aString 121 | { 122 | /** 123 | * **************************************** START *************************************** 124 | * 之前PPGetAddressBook对联系人排序时在中文转拼音这一部分非常耗时 125 | * 参考博主-庞海礁先生的一文:iOS开发中如何更快的实现汉字转拼音 http://www.olinone.com/?p=131 126 | * 使PPGetAddressBook对联系人排序的性能提升 3~6倍, 非常感谢! 127 | */ 128 | NSMutableString *mutableString = [NSMutableString stringWithString:aString]; 129 | CFStringTransform((CFMutableStringRef)mutableString, NULL, kCFStringTransformToLatin, false); 130 | NSString *pinyinString = [mutableString stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]]; 131 | /** 132 | * *************************************** END ****************************************** 133 | */ 134 | 135 | // 将拼音首字母装换成大写 136 | NSString *strPinYin = [[self polyphoneStringHandle:aString pinyinString:pinyinString] uppercaseString]; 137 | // 截取大写首字母 138 | NSString *firstString = [strPinYin substringToIndex:1]; 139 | // 判断姓名首位是否为大写字母 140 | NSString * regexA = @"^[A-Z]$"; 141 | NSPredicate *predA = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexA]; 142 | // 获取并返回首字母 143 | return [predA evaluateWithObject:firstString] ? firstString : @"#"; 144 | 145 | } 146 | 147 | /** 148 | 多音字处理 149 | */ 150 | + (NSString *)polyphoneStringHandle:(NSString *)aString pinyinString:(NSString *)pinyinString 151 | { 152 | if ([aString hasPrefix:@"长"]) { return @"chang";} 153 | if ([aString hasPrefix:@"沈"]) { return @"shen"; } 154 | if ([aString hasPrefix:@"厦"]) { return @"xia"; } 155 | if ([aString hasPrefix:@"地"]) { return @"di"; } 156 | if ([aString hasPrefix:@"重"]) { return @"chong";} 157 | return pinyinString; 158 | } 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPPersonModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPAddressModel.h 3 | // PPAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | /* 10 | ********************************************************************************* 11 | * 12 | *⭐️⭐️⭐️ 新建 PP-iOS学习交流群: 323408051 欢迎加入!!! ⭐️⭐️⭐️ 13 | * 14 | * 如果您在使用 PPGetAddressBook 的过程中出现bug或有更好的建议,还请及时以下列方式联系我,我会及 15 | * 时修复bug,解决问题. 16 | * 17 | * Weibo : jkpang-庞 18 | * Email : jkpang@outlook.com 19 | * QQ 群 : 323408051 20 | * GitHub: https://github.com/jkpang 21 | * 22 | * PS:我的另外两个很好用的封装,欢迎使用! 23 | * 1.对AFNetworking 3.x 与YYCache的二次封装,一句代码搞定数据请求与缓存,告别FMDB: 24 | * GitHub:https://github.com/jkpang/PPNetworkHelper 25 | * 2.仿京东淘宝商品数量的加减按钮,可定制程度高,使用简单: 26 | * GitHub:https://github.com/jkpang/PPNumberButton 27 | * 28 | * 如果 PPGetAddressBook 好用,希望您能Star支持,你的 ⭐️ 是我持续更新的动力! 29 | ********************************************************************************* 30 | */ 31 | 32 | #import 33 | #import 34 | 35 | @interface PPPersonModel : NSObject 36 | 37 | /** 联系人姓名*/ 38 | @property (nonatomic, copy) NSString *name; 39 | /** 联系人电话数组,因为一个联系人可能存储多个号码*/ 40 | @property (nonatomic, strong) NSMutableArray *mobileArray; 41 | /** 联系人头像*/ 42 | @property (nonatomic, strong) UIImage *headerImage; 43 | 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPPersonModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPAddressModel.m 3 | // PPAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import "PPPersonModel.h" 10 | 11 | @implementation PPPersonModel 12 | 13 | - (NSMutableArray *)mobileArray 14 | { 15 | if(!_mobileArray) 16 | { 17 | _mobileArray = [NSMutableArray array]; 18 | } 19 | return _mobileArray; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /PPGetAddressBook/PPGetAddressBook/PPSingleton.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // PPSingleton.h 4 | // PPGetAddressBook 5 | // 6 | // Created by AndyPang on 16/9/19. 7 | // Copyright © 2016年 AndyPang. All rights reserved. 8 | // 9 | 10 | /* 11 | ********************************************************************************* 12 | * 13 | *⭐️⭐️⭐️ 新建 PP-iOS学习交流群: 323408051 欢迎加入!!! ⭐️⭐️⭐️ 14 | * 15 | * 如果您在使用 PPGetAddressBook 的过程中出现bug或有更好的建议,还请及时以下列方式联系我,我会及 16 | * 时修复bug,解决问题. 17 | * 18 | * Weibo : jkpang-庞 19 | * Email : jkpang@outlook.com 20 | * QQ 群 : 323408051 21 | * GitHub: https://github.com/jkpang 22 | * 23 | * PS:我的另外两个很好用的封装,欢迎使用! 24 | * 1.对AFNetworking 3.x 与YYCache的二次封装,一句代码搞定数据请求与缓存,告别FMDB: 25 | * GitHub:https://github.com/jkpang/PPNetworkHelper 26 | * 2.仿京东淘宝商品数量的加减按钮,可定制程度高,使用简单: 27 | * GitHub:https://github.com/jkpang/PPNumberButton 28 | * 29 | * 如果 PPGetAddressBook 好用,希望您能Star支持,你的 ⭐️ 是我持续更新的动力! 30 | ********************************************************************************* 31 | */ 32 | 33 | #ifndef PPSingleton_h 34 | #define PPSingleton_h 35 | 36 | // .h文件 37 | #define PPSingletonH(name) + (instancetype)shared##name; 38 | 39 | // .m文件 40 | #define PPSingletonM(name) \ 41 | static id _instance; \ 42 | \ 43 | + (instancetype)allocWithZone:(struct _NSZone *)zone \ 44 | { \ 45 | static dispatch_once_t onceToken; \ 46 | dispatch_once(&onceToken, ^{ \ 47 | _instance = [super allocWithZone:zone]; \ 48 | }); \ 49 | return _instance; \ 50 | } \ 51 | \ 52 | + (instancetype)shared##name \ 53 | { \ 54 | static dispatch_once_t onceToken; \ 55 | dispatch_once(&onceToken, ^{ \ 56 | _instance = [[self alloc] init]; \ 57 | }); \ 58 | return _instance; \ 59 | } \ 60 | \ 61 | - (id)copyWithZone:(NSZone *)zone \ 62 | { \ 63 | return _instance; \ 64 | } 65 | 66 | #endif /* PPSingleton_h */ 67 | -------------------------------------------------------------------------------- /PPGetAddressBook/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /PPGetAddressBook/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | /* 10 | ********************************************************************************* 11 | * 12 | *⭐️⭐️⭐️ 新建 PP-iOS学习交流群: 323408051 欢迎加入!!! ⭐️⭐️⭐️ 13 | * 14 | * 如果您在使用 PPGetAddressBook 的过程中出现bug或有更好的建议,还请及时以下列方式联系我,我会及 15 | * 时修复bug,解决问题. 16 | * 17 | * Weibo : jkpang-庞 18 | * Email : jkpang@outlook.com 19 | * QQ 群 : 323408051 20 | * GitHub: https://github.com/jkpang 21 | * 22 | * PS:我的另外两个很好用的封装,欢迎使用! 23 | * 1.对AFNetworking 3.x 与YYCache的二次封装,一句代码搞定数据请求与缓存,告别FMDB: 24 | * GitHub:https://github.com/jkpang/PPNetworkHelper 25 | * 2.仿京东淘宝商品数量的加减按钮,可定制程度高,使用简单: 26 | * GitHub:https://github.com/jkpang/PPNumberButton 27 | * 28 | * 如果 PPGetAddressBook 好用,希望您能Star支持,你的 ⭐️ 是我持续更新的动力! 29 | ********************************************************************************* 30 | */ 31 | 32 | #import "ViewController.h" 33 | #import "AddressBookController1.h" 34 | #import "AddressBookController2.h" 35 | 36 | 37 | @interface ViewController () 38 | 39 | @property (nonatomic, copy) NSArray *dataSource; 40 | 41 | @end 42 | 43 | @implementation ViewController 44 | 45 | - (void)viewDidLoad { 46 | [super viewDidLoad]; 47 | 48 | self.navigationItem.title = @"PPGetAddressBook"; 49 | 50 | _dataSource = @[@"A~Z顺序排列 - AddressBookController1",@"原始顺序 - AddressBookController2"]; 51 | 52 | UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; 53 | tableView.delegate = self; 54 | tableView.dataSource = self; 55 | [self.view addSubview:tableView]; 56 | 57 | } 58 | 59 | #pragma mark - UITableViewDataSource 60 | 61 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 62 | { 63 | return _dataSource.count; 64 | } 65 | 66 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 67 | { 68 | static NSString *reuseIdentifier = @"cell"; 69 | 70 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; 71 | if (!cell) 72 | { 73 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 74 | } 75 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 76 | cell.textLabel.text = _dataSource[indexPath.row]; 77 | return cell; 78 | } 79 | 80 | #pragma mark - UITableViewDelegate 81 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 82 | { 83 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 84 | static UIViewController *VC; 85 | 86 | if(indexPath.row == 0) 87 | { 88 | VC = [AddressBookController1 new]; 89 | } 90 | else 91 | { 92 | VC = [AddressBookController2 new]; 93 | } 94 | [self.navigationController pushViewController:VC animated:YES]; 95 | } 96 | 97 | 98 | 99 | 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /PPGetAddressBook/defult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/PPGetAddressBook/defult.png -------------------------------------------------------------------------------- /PPGetAddressBook/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PPGetAddressBook 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PPGetAddressBookTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /PPGetAddressBookTests/PPGetAddressBookTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPGetAddressBookTests.m 3 | // PPGetAddressBookTests 4 | // 5 | // Created by AndyPang on 16/8/17. 6 | // Copyright © 2016年 AndyPang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PPGetAddressBookTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation PPGetAddressBookTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Picture/AddressBook.mov.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/Picture/AddressBook.mov.gif -------------------------------------------------------------------------------- /Picture/PPGetAddressBook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkpang/PPGetAddressBook/ed620972b46ed71916294c9cebc2c0dad7fa82f5/Picture/PPGetAddressBook.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://github.com/jkpang/PPGetAddressBook/blob/master/Picture/PPGetAddressBook.png) 2 | 3 | ![](https://img.shields.io/badge/platform-iOS-red.svg) ![](https://img.shields.io/badge/language-Objective--C-orange.svg) ![](https://img.shields.io/cocoapods/v/PPGetAddressBook.svg?style=flat) ![](https://img.shields.io/cocoapods/dt/PPGetAddressBook.svg) ![](https://img.shields.io/badge/license-MIT%20License-brightgreen.svg) [![](https://img.shields.io/badge/weibo-jkpang--%E5%BA%9E-red.svg)](http://weibo.com/5743737098/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1) 4 | 5 | * PPGetAddressBook对AddressBook框架(iOS9之前)和Contacts框架(iOS9之后)做了对应的封装处理; 6 | 7 | * 支持一句代码获取按联系人姓名首字拼音A~Z排序(*重点:已处理姓名所有字符的排序问题,排序更准确!*); 8 | * 支持一句代码获取原始顺序的联系人,未分组,可自行处理; 9 | * 已对号码中的"+86","-","()",空号和联系人姓名空白做了处理,不会出现因为数据源NULL导致程序crash的问题; 10 | * 对姓"长","沈","厦","地","冲"多音字进行优化处理. 11 | 12 | ### 新建 PP-iOS学习交流群 : 323408051 有关于PP系列封装的问题和iOS技术可以在此群讨论 13 | 14 | [简书地址](http://www.jianshu.com/p/b51a6125bcff) ; [codeData 地址](http://www.codedata.cn/cdetail/Objective-C/Demo/1471619974294285) 15 | 16 | #### 如果你需要Swift版本,请戳: https://github.com/jkpang/PPGetAddressBookSwift 17 | 18 | ![image](https://github.com/jkpang/PPGetAddressBook/blob/master/Picture/AddressBook.mov.gif) 19 | 20 | ## Requirements 要求 21 | * iOS 7+ 22 | * Xcode 8+ 23 | 24 | ## Installation 安装 25 | ### 1.手动安装: 26 | `下载DEMO后,将子文件夹PPGetAddressBook拖入到项目中, 导入头文件PPGetAddressBook.h开始使用` 27 | ### 2.CocoaPods安装: 28 | first 29 | `pod 'PPGetAddressBook',:git => 'https://github.com/jkpang/PPGetAddressBook.git'` 30 | 31 | then 32 | `pod install或pod install --no-repo-update` 33 | 34 | 如果发现pod search PPGetAddressBook 不是最新版本,在终端执行pod setup命令更新本地spec镜像缓存(时间可能有点长),重新搜索就OK了 35 | ## Usage 使用方法 36 | ****注意, 在iOS 10系统下必须在info.plist文件中配置获取隐私数据权限声明 : [兼容iOS 10:配置获取隐私数据权限声明 37 | ](http://www.jianshu.com/p/616240463a7a)*** 38 | ### 一、首先必须要请求用户是否授权APP访问通讯录的权限(建议在APPDeletegate.m中的didFinishLaunchingWithOptions方法中调用) 39 | 40 | ```objc 41 | //请求用户获取通讯录权限 42 | [PPGetAddressBook requestAddressBookAuthorization]; 43 | ``` 44 | ### 二、获取通讯录 45 | ### 1.获取按联系人姓名首字拼音A~Z排序(已处理姓名所有字符的排序问题),一句话搞定! 46 | 47 | ```objc 48 | //获取按联系人姓名首字拼音A~Z排序(已经对姓名的第二个字做了处理) 49 | [PPGetAddressBook getOrderAddressBook:^(NSDictionary *addressBookDict, NSArray *nameKeys) { 50 | //addressBookDict: 装着所有联系人的字典 51 | //nameKeys: A~Z拼音字母数组; 52 | //刷新 tableView 53 | [self.tableView reloadData]; 54 | } authorizationFailure:^{ 55 | NSLog(@"请在iPhone的“设置-隐私-通讯录”选项中,允许PPAddressBook访问您的通讯录"); 56 | }]; 57 | 58 | 59 | ``` 60 | ### 2.获取原始顺序的联系人模型,未分组,一句话搞定! 61 | 62 | ```objc 63 | //获取没有经过排序的联系人模型 64 | [PPGetAddressBook getOriginalAddressBook:^(NSArray *addressBookArray) { 65 | //addressBookArray:原始顺序的联系人模型数组 66 | 67 | //刷新 tableView 68 | [self.tableView reloadData]; 69 | } authorizationFailure:^{ 70 | NSLog(@"请在iPhone的“设置-隐私-通讯录”选项中,允许PPAddressBook访问您的通讯录"); 71 | }]; 72 | 73 | ``` 74 | 75 | 如果你有更好的实现方法,希望不吝赐教! 76 | #### 你的star是我持续更新的动力! 77 | === 78 | ## CocoaPods更新日志 79 | * 2016.12.01(tag:0.2.8)--修复在iOS 9之前系统中编辑联系人不会及时同步的bug 80 | * 2016.10.30(tag:0.2.7)--1.对姓"长","沈","厦","地","冲"多音字进行优化处理; 2.将'#'key值排列在A~Z的末尾! 81 | * 2016.10.08(tag:0.2.6)--读取联系人速度再次提升! 82 | * 2016.09.16(tag:0.2.5)--读取排序通讯录时性能提升3~6倍以及部分代码优化,推荐使用此版本及之后的版本 83 | * 2016.09.12(tag:0.2.2)--小细节优化 84 | * 2016.09.01(tag:0.2.1)--修复 当用户没有授权时程序卡死的Bug 85 | * 2016.08.26(tag:0.2.0)--将联系人排序的耗时操作放在子线程,大大优化程序的载入速度与体验 86 | * 2016.08.23(tag:0.1.2)--小细节优化 87 | * 2016.08.21(tag:0.1.1)--Pods初始化 88 | 89 | ## 我的App <-> My APP 90 | - [PPHub](https://github.com/jkpang/PPHub-Feedback):一个简洁漂亮的 GitHub iOS客户端 <-> A simple and beautiful GitHub iOS client 91 | [![App_Store](https://github.com/jkpang/PPHub-Feedback/blob/master/Resource/Download_on_the_App_Store_135x40.svg)](https://itunes.apple.com/cn/app/PPHub%20For%20GitHub/id1314212521?mt=8) 92 | 93 | ## 联系方式: 94 | * Weibo : [@jkpang-庞](http://weibo.com/5743737098/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1) 95 | * Email : jkpang@outlook.com 96 | * QQ群 : 323408051 97 | 98 | ![PP-iOS学习交流群群二维码](https://github.com/jkpang/PPCounter/blob/master/PP-iOS%E5%AD%A6%E4%B9%A0%E4%BA%A4%E6%B5%81%E7%BE%A4%E7%BE%A4%E4%BA%8C%E7%BB%B4%E7%A0%81.png) 99 | 100 | ## 许可证 101 | PPGetAddressBook 使用 MIT 许可证,详情见 LICENSE 文件。 102 | 103 | 104 | 105 | 106 | --------------------------------------------------------------------------------