├── PinYinSwiftDemo ├── PinYinSwiftDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ └── hlc.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── hlc.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── PinYinSwiftDemo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── PinYinSwift │ │ ├── String+filtering.swift │ │ ├── configuration.swift │ │ ├── contentFormatter.swift │ │ ├── pinyinResource.swift │ │ ├── unicode_sentenceto_pinyin.txt │ │ └── unicode_to_hanyu_pinyin.txt │ ├── SceneDelegate.swift │ └── ViewController.swift ├── PinYinSwiftDemoTests │ ├── Info.plist │ └── PinYinSwiftDemoTests.swift └── PinYinSwiftDemoUITests │ ├── Info.plist │ └── PinYinSwiftDemoUITests.swift └── README.md /PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6E32E7A9259E12D300EAB42C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7A8259E12D300EAB42C /* AppDelegate.swift */; }; 11 | 6E32E7AB259E12D300EAB42C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7AA259E12D300EAB42C /* SceneDelegate.swift */; }; 12 | 6E32E7AD259E12D300EAB42C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7AC259E12D300EAB42C /* ViewController.swift */; }; 13 | 6E32E7B0259E12D300EAB42C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E32E7AE259E12D300EAB42C /* Main.storyboard */; }; 14 | 6E32E7B2259E12D500EAB42C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6E32E7B1259E12D500EAB42C /* Assets.xcassets */; }; 15 | 6E32E7B5259E12D500EAB42C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E32E7B3259E12D500EAB42C /* LaunchScreen.storyboard */; }; 16 | 6E32E7C0259E12D500EAB42C /* PinYinSwiftDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7BF259E12D500EAB42C /* PinYinSwiftDemoTests.swift */; }; 17 | 6E32E7CB259E12D600EAB42C /* PinYinSwiftDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7CA259E12D600EAB42C /* PinYinSwiftDemoUITests.swift */; }; 18 | 6E32E7E2259E12F800EAB42C /* unicode_sentenceto_pinyin.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6E32E7DC259E12F800EAB42C /* unicode_sentenceto_pinyin.txt */; }; 19 | 6E32E7E3259E12F800EAB42C /* unicode_to_hanyu_pinyin.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6E32E7DD259E12F800EAB42C /* unicode_to_hanyu_pinyin.txt */; }; 20 | 6E32E7E4259E12F800EAB42C /* contentFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7DE259E12F800EAB42C /* contentFormatter.swift */; }; 21 | 6E32E7E5259E12F800EAB42C /* String+filtering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7DF259E12F800EAB42C /* String+filtering.swift */; }; 22 | 6E32E7E6259E12F800EAB42C /* pinyinResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7E0259E12F800EAB42C /* pinyinResource.swift */; }; 23 | 6E32E7E7259E12F800EAB42C /* configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E32E7E1259E12F800EAB42C /* configuration.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 6E32E7BC259E12D500EAB42C /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 6E32E79D259E12D300EAB42C /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 6E32E7A4259E12D300EAB42C; 32 | remoteInfo = PinYinSwiftDemo; 33 | }; 34 | 6E32E7C7259E12D600EAB42C /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 6E32E79D259E12D300EAB42C /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 6E32E7A4259E12D300EAB42C; 39 | remoteInfo = PinYinSwiftDemo; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 6E32E7A5259E12D300EAB42C /* PinYinSwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PinYinSwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 6E32E7A8259E12D300EAB42C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46 | 6E32E7AA259E12D300EAB42C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 47 | 6E32E7AC259E12D300EAB42C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 48 | 6E32E7AF259E12D300EAB42C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | 6E32E7B1259E12D500EAB42C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 6E32E7B4259E12D500EAB42C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 6E32E7B6259E12D500EAB42C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 6E32E7BB259E12D500EAB42C /* PinYinSwiftDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PinYinSwiftDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 6E32E7BF259E12D500EAB42C /* PinYinSwiftDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinYinSwiftDemoTests.swift; sourceTree = ""; }; 54 | 6E32E7C1259E12D500EAB42C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 6E32E7C6259E12D600EAB42C /* PinYinSwiftDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PinYinSwiftDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 6E32E7CA259E12D600EAB42C /* PinYinSwiftDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinYinSwiftDemoUITests.swift; sourceTree = ""; }; 57 | 6E32E7CC259E12D600EAB42C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 6E32E7DC259E12F800EAB42C /* unicode_sentenceto_pinyin.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = unicode_sentenceto_pinyin.txt; sourceTree = ""; }; 59 | 6E32E7DD259E12F800EAB42C /* unicode_to_hanyu_pinyin.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = unicode_to_hanyu_pinyin.txt; sourceTree = ""; }; 60 | 6E32E7DE259E12F800EAB42C /* contentFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = contentFormatter.swift; sourceTree = ""; }; 61 | 6E32E7DF259E12F800EAB42C /* String+filtering.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+filtering.swift"; sourceTree = ""; }; 62 | 6E32E7E0259E12F800EAB42C /* pinyinResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = pinyinResource.swift; sourceTree = ""; }; 63 | 6E32E7E1259E12F800EAB42C /* configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = configuration.swift; sourceTree = ""; }; 64 | /* End PBXFileReference section */ 65 | 66 | /* Begin PBXFrameworksBuildPhase section */ 67 | 6E32E7A2259E12D300EAB42C /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | 6E32E7B8259E12D500EAB42C /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | 6E32E7C3259E12D600EAB42C /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 6E32E79C259E12D300EAB42C = { 92 | isa = PBXGroup; 93 | children = ( 94 | 6E32E7A7259E12D300EAB42C /* PinYinSwiftDemo */, 95 | 6E32E7BE259E12D500EAB42C /* PinYinSwiftDemoTests */, 96 | 6E32E7C9259E12D600EAB42C /* PinYinSwiftDemoUITests */, 97 | 6E32E7A6259E12D300EAB42C /* Products */, 98 | ); 99 | sourceTree = ""; 100 | }; 101 | 6E32E7A6259E12D300EAB42C /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 6E32E7A5259E12D300EAB42C /* PinYinSwiftDemo.app */, 105 | 6E32E7BB259E12D500EAB42C /* PinYinSwiftDemoTests.xctest */, 106 | 6E32E7C6259E12D600EAB42C /* PinYinSwiftDemoUITests.xctest */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 6E32E7A7259E12D300EAB42C /* PinYinSwiftDemo */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 6E32E7DB259E12F800EAB42C /* PinYinSwift */, 115 | 6E32E7A8259E12D300EAB42C /* AppDelegate.swift */, 116 | 6E32E7AA259E12D300EAB42C /* SceneDelegate.swift */, 117 | 6E32E7AC259E12D300EAB42C /* ViewController.swift */, 118 | 6E32E7AE259E12D300EAB42C /* Main.storyboard */, 119 | 6E32E7B1259E12D500EAB42C /* Assets.xcassets */, 120 | 6E32E7B3259E12D500EAB42C /* LaunchScreen.storyboard */, 121 | 6E32E7B6259E12D500EAB42C /* Info.plist */, 122 | ); 123 | path = PinYinSwiftDemo; 124 | sourceTree = ""; 125 | }; 126 | 6E32E7BE259E12D500EAB42C /* PinYinSwiftDemoTests */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 6E32E7BF259E12D500EAB42C /* PinYinSwiftDemoTests.swift */, 130 | 6E32E7C1259E12D500EAB42C /* Info.plist */, 131 | ); 132 | path = PinYinSwiftDemoTests; 133 | sourceTree = ""; 134 | }; 135 | 6E32E7C9259E12D600EAB42C /* PinYinSwiftDemoUITests */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 6E32E7CA259E12D600EAB42C /* PinYinSwiftDemoUITests.swift */, 139 | 6E32E7CC259E12D600EAB42C /* Info.plist */, 140 | ); 141 | path = PinYinSwiftDemoUITests; 142 | sourceTree = ""; 143 | }; 144 | 6E32E7DB259E12F800EAB42C /* PinYinSwift */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 6E32E7DC259E12F800EAB42C /* unicode_sentenceto_pinyin.txt */, 148 | 6E32E7DD259E12F800EAB42C /* unicode_to_hanyu_pinyin.txt */, 149 | 6E32E7DE259E12F800EAB42C /* contentFormatter.swift */, 150 | 6E32E7DF259E12F800EAB42C /* String+filtering.swift */, 151 | 6E32E7E0259E12F800EAB42C /* pinyinResource.swift */, 152 | 6E32E7E1259E12F800EAB42C /* configuration.swift */, 153 | ); 154 | path = PinYinSwift; 155 | sourceTree = ""; 156 | }; 157 | /* End PBXGroup section */ 158 | 159 | /* Begin PBXNativeTarget section */ 160 | 6E32E7A4259E12D300EAB42C /* PinYinSwiftDemo */ = { 161 | isa = PBXNativeTarget; 162 | buildConfigurationList = 6E32E7CF259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemo" */; 163 | buildPhases = ( 164 | 6E32E7A1259E12D300EAB42C /* Sources */, 165 | 6E32E7A2259E12D300EAB42C /* Frameworks */, 166 | 6E32E7A3259E12D300EAB42C /* Resources */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | ); 172 | name = PinYinSwiftDemo; 173 | productName = PinYinSwiftDemo; 174 | productReference = 6E32E7A5259E12D300EAB42C /* PinYinSwiftDemo.app */; 175 | productType = "com.apple.product-type.application"; 176 | }; 177 | 6E32E7BA259E12D500EAB42C /* PinYinSwiftDemoTests */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = 6E32E7D2259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemoTests" */; 180 | buildPhases = ( 181 | 6E32E7B7259E12D500EAB42C /* Sources */, 182 | 6E32E7B8259E12D500EAB42C /* Frameworks */, 183 | 6E32E7B9259E12D500EAB42C /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | 6E32E7BD259E12D500EAB42C /* PBXTargetDependency */, 189 | ); 190 | name = PinYinSwiftDemoTests; 191 | productName = PinYinSwiftDemoTests; 192 | productReference = 6E32E7BB259E12D500EAB42C /* PinYinSwiftDemoTests.xctest */; 193 | productType = "com.apple.product-type.bundle.unit-test"; 194 | }; 195 | 6E32E7C5259E12D600EAB42C /* PinYinSwiftDemoUITests */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 6E32E7D5259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemoUITests" */; 198 | buildPhases = ( 199 | 6E32E7C2259E12D600EAB42C /* Sources */, 200 | 6E32E7C3259E12D600EAB42C /* Frameworks */, 201 | 6E32E7C4259E12D600EAB42C /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | 6E32E7C8259E12D600EAB42C /* PBXTargetDependency */, 207 | ); 208 | name = PinYinSwiftDemoUITests; 209 | productName = PinYinSwiftDemoUITests; 210 | productReference = 6E32E7C6259E12D600EAB42C /* PinYinSwiftDemoUITests.xctest */; 211 | productType = "com.apple.product-type.bundle.ui-testing"; 212 | }; 213 | /* End PBXNativeTarget section */ 214 | 215 | /* Begin PBXProject section */ 216 | 6E32E79D259E12D300EAB42C /* Project object */ = { 217 | isa = PBXProject; 218 | attributes = { 219 | LastSwiftUpdateCheck = 1220; 220 | LastUpgradeCheck = 1220; 221 | TargetAttributes = { 222 | 6E32E7A4259E12D300EAB42C = { 223 | CreatedOnToolsVersion = 12.2; 224 | }; 225 | 6E32E7BA259E12D500EAB42C = { 226 | CreatedOnToolsVersion = 12.2; 227 | TestTargetID = 6E32E7A4259E12D300EAB42C; 228 | }; 229 | 6E32E7C5259E12D600EAB42C = { 230 | CreatedOnToolsVersion = 12.2; 231 | TestTargetID = 6E32E7A4259E12D300EAB42C; 232 | }; 233 | }; 234 | }; 235 | buildConfigurationList = 6E32E7A0259E12D300EAB42C /* Build configuration list for PBXProject "PinYinSwiftDemo" */; 236 | compatibilityVersion = "Xcode 9.3"; 237 | developmentRegion = en; 238 | hasScannedForEncodings = 0; 239 | knownRegions = ( 240 | en, 241 | Base, 242 | ); 243 | mainGroup = 6E32E79C259E12D300EAB42C; 244 | productRefGroup = 6E32E7A6259E12D300EAB42C /* Products */; 245 | projectDirPath = ""; 246 | projectRoot = ""; 247 | targets = ( 248 | 6E32E7A4259E12D300EAB42C /* PinYinSwiftDemo */, 249 | 6E32E7BA259E12D500EAB42C /* PinYinSwiftDemoTests */, 250 | 6E32E7C5259E12D600EAB42C /* PinYinSwiftDemoUITests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 6E32E7A3259E12D300EAB42C /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 6E32E7B5259E12D500EAB42C /* LaunchScreen.storyboard in Resources */, 261 | 6E32E7B2259E12D500EAB42C /* Assets.xcassets in Resources */, 262 | 6E32E7B0259E12D300EAB42C /* Main.storyboard in Resources */, 263 | 6E32E7E2259E12F800EAB42C /* unicode_sentenceto_pinyin.txt in Resources */, 264 | 6E32E7E3259E12F800EAB42C /* unicode_to_hanyu_pinyin.txt in Resources */, 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | 6E32E7B9259E12D500EAB42C /* Resources */ = { 269 | isa = PBXResourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | 6E32E7C4259E12D600EAB42C /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXResourcesBuildPhase section */ 283 | 284 | /* Begin PBXSourcesBuildPhase section */ 285 | 6E32E7A1259E12D300EAB42C /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 6E32E7E7259E12F800EAB42C /* configuration.swift in Sources */, 290 | 6E32E7E4259E12F800EAB42C /* contentFormatter.swift in Sources */, 291 | 6E32E7E5259E12F800EAB42C /* String+filtering.swift in Sources */, 292 | 6E32E7AD259E12D300EAB42C /* ViewController.swift in Sources */, 293 | 6E32E7A9259E12D300EAB42C /* AppDelegate.swift in Sources */, 294 | 6E32E7E6259E12F800EAB42C /* pinyinResource.swift in Sources */, 295 | 6E32E7AB259E12D300EAB42C /* SceneDelegate.swift in Sources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | 6E32E7B7259E12D500EAB42C /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 6E32E7C0259E12D500EAB42C /* PinYinSwiftDemoTests.swift in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | 6E32E7C2259E12D600EAB42C /* Sources */ = { 308 | isa = PBXSourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | 6E32E7CB259E12D600EAB42C /* PinYinSwiftDemoUITests.swift in Sources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | /* End PBXSourcesBuildPhase section */ 316 | 317 | /* Begin PBXTargetDependency section */ 318 | 6E32E7BD259E12D500EAB42C /* PBXTargetDependency */ = { 319 | isa = PBXTargetDependency; 320 | target = 6E32E7A4259E12D300EAB42C /* PinYinSwiftDemo */; 321 | targetProxy = 6E32E7BC259E12D500EAB42C /* PBXContainerItemProxy */; 322 | }; 323 | 6E32E7C8259E12D600EAB42C /* PBXTargetDependency */ = { 324 | isa = PBXTargetDependency; 325 | target = 6E32E7A4259E12D300EAB42C /* PinYinSwiftDemo */; 326 | targetProxy = 6E32E7C7259E12D600EAB42C /* PBXContainerItemProxy */; 327 | }; 328 | /* End PBXTargetDependency section */ 329 | 330 | /* Begin PBXVariantGroup section */ 331 | 6E32E7AE259E12D300EAB42C /* Main.storyboard */ = { 332 | isa = PBXVariantGroup; 333 | children = ( 334 | 6E32E7AF259E12D300EAB42C /* Base */, 335 | ); 336 | name = Main.storyboard; 337 | sourceTree = ""; 338 | }; 339 | 6E32E7B3259E12D500EAB42C /* LaunchScreen.storyboard */ = { 340 | isa = PBXVariantGroup; 341 | children = ( 342 | 6E32E7B4259E12D500EAB42C /* Base */, 343 | ); 344 | name = LaunchScreen.storyboard; 345 | sourceTree = ""; 346 | }; 347 | /* End PBXVariantGroup section */ 348 | 349 | /* Begin XCBuildConfiguration section */ 350 | 6E32E7CD259E12D600EAB42C /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ALWAYS_SEARCH_USER_PATHS = NO; 354 | CLANG_ANALYZER_NONNULL = YES; 355 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 356 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 357 | CLANG_CXX_LIBRARY = "libc++"; 358 | CLANG_ENABLE_MODULES = YES; 359 | CLANG_ENABLE_OBJC_ARC = YES; 360 | CLANG_ENABLE_OBJC_WEAK = YES; 361 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 362 | CLANG_WARN_BOOL_CONVERSION = YES; 363 | CLANG_WARN_COMMA = YES; 364 | CLANG_WARN_CONSTANT_CONVERSION = YES; 365 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 366 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 367 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INFINITE_RECURSION = YES; 371 | CLANG_WARN_INT_CONVERSION = YES; 372 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 373 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 374 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 375 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 376 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 377 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 378 | CLANG_WARN_STRICT_PROTOTYPES = YES; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | COPY_PHASE_STRIP = NO; 384 | DEBUG_INFORMATION_FORMAT = dwarf; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | ENABLE_TESTABILITY = YES; 387 | GCC_C_LANGUAGE_STANDARD = gnu11; 388 | GCC_DYNAMIC_NO_PIC = NO; 389 | GCC_NO_COMMON_BLOCKS = YES; 390 | GCC_OPTIMIZATION_LEVEL = 0; 391 | GCC_PREPROCESSOR_DEFINITIONS = ( 392 | "DEBUG=1", 393 | "$(inherited)", 394 | ); 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 402 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 403 | MTL_FAST_MATH = YES; 404 | ONLY_ACTIVE_ARCH = YES; 405 | SDKROOT = iphoneos; 406 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 407 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 408 | }; 409 | name = Debug; 410 | }; 411 | 6E32E7CE259E12D600EAB42C /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ALWAYS_SEARCH_USER_PATHS = NO; 415 | CLANG_ANALYZER_NONNULL = YES; 416 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 417 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 418 | CLANG_CXX_LIBRARY = "libc++"; 419 | CLANG_ENABLE_MODULES = YES; 420 | CLANG_ENABLE_OBJC_ARC = YES; 421 | CLANG_ENABLE_OBJC_WEAK = YES; 422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_COMMA = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 427 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 428 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 429 | CLANG_WARN_EMPTY_BODY = YES; 430 | CLANG_WARN_ENUM_CONVERSION = YES; 431 | CLANG_WARN_INFINITE_RECURSION = YES; 432 | CLANG_WARN_INT_CONVERSION = YES; 433 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 434 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 435 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 436 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 437 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 438 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 439 | CLANG_WARN_STRICT_PROTOTYPES = YES; 440 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 441 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 442 | CLANG_WARN_UNREACHABLE_CODE = YES; 443 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 444 | COPY_PHASE_STRIP = NO; 445 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 446 | ENABLE_NS_ASSERTIONS = NO; 447 | ENABLE_STRICT_OBJC_MSGSEND = YES; 448 | GCC_C_LANGUAGE_STANDARD = gnu11; 449 | GCC_NO_COMMON_BLOCKS = YES; 450 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 451 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 452 | GCC_WARN_UNDECLARED_SELECTOR = YES; 453 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 454 | GCC_WARN_UNUSED_FUNCTION = YES; 455 | GCC_WARN_UNUSED_VARIABLE = YES; 456 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 457 | MTL_ENABLE_DEBUG_INFO = NO; 458 | MTL_FAST_MATH = YES; 459 | SDKROOT = iphoneos; 460 | SWIFT_COMPILATION_MODE = wholemodule; 461 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 462 | VALIDATE_PRODUCT = YES; 463 | }; 464 | name = Release; 465 | }; 466 | 6E32E7D0259E12D600EAB42C /* Debug */ = { 467 | isa = XCBuildConfiguration; 468 | buildSettings = { 469 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 470 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 471 | CODE_SIGN_STYLE = Automatic; 472 | INFOPLIST_FILE = PinYinSwiftDemo/Info.plist; 473 | LD_RUNPATH_SEARCH_PATHS = ( 474 | "$(inherited)", 475 | "@executable_path/Frameworks", 476 | ); 477 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemo; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | SWIFT_VERSION = 5.0; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 6E32E7D1259E12D600EAB42C /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 488 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 489 | CODE_SIGN_STYLE = Automatic; 490 | INFOPLIST_FILE = PinYinSwiftDemo/Info.plist; 491 | LD_RUNPATH_SEARCH_PATHS = ( 492 | "$(inherited)", 493 | "@executable_path/Frameworks", 494 | ); 495 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemo; 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | SWIFT_VERSION = 5.0; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | }; 500 | name = Release; 501 | }; 502 | 6E32E7D3259E12D600EAB42C /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 506 | BUNDLE_LOADER = "$(TEST_HOST)"; 507 | CODE_SIGN_STYLE = Automatic; 508 | INFOPLIST_FILE = PinYinSwiftDemoTests/Info.plist; 509 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 510 | LD_RUNPATH_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "@executable_path/Frameworks", 513 | "@loader_path/Frameworks", 514 | ); 515 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemoTests; 516 | PRODUCT_NAME = "$(TARGET_NAME)"; 517 | SWIFT_VERSION = 5.0; 518 | TARGETED_DEVICE_FAMILY = "1,2"; 519 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PinYinSwiftDemo.app/PinYinSwiftDemo"; 520 | }; 521 | name = Debug; 522 | }; 523 | 6E32E7D4259E12D600EAB42C /* Release */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 527 | BUNDLE_LOADER = "$(TEST_HOST)"; 528 | CODE_SIGN_STYLE = Automatic; 529 | INFOPLIST_FILE = PinYinSwiftDemoTests/Info.plist; 530 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 531 | LD_RUNPATH_SEARCH_PATHS = ( 532 | "$(inherited)", 533 | "@executable_path/Frameworks", 534 | "@loader_path/Frameworks", 535 | ); 536 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemoTests; 537 | PRODUCT_NAME = "$(TARGET_NAME)"; 538 | SWIFT_VERSION = 5.0; 539 | TARGETED_DEVICE_FAMILY = "1,2"; 540 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PinYinSwiftDemo.app/PinYinSwiftDemo"; 541 | }; 542 | name = Release; 543 | }; 544 | 6E32E7D6259E12D600EAB42C /* Debug */ = { 545 | isa = XCBuildConfiguration; 546 | buildSettings = { 547 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 548 | CODE_SIGN_STYLE = Automatic; 549 | INFOPLIST_FILE = PinYinSwiftDemoUITests/Info.plist; 550 | LD_RUNPATH_SEARCH_PATHS = ( 551 | "$(inherited)", 552 | "@executable_path/Frameworks", 553 | "@loader_path/Frameworks", 554 | ); 555 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemoUITests; 556 | PRODUCT_NAME = "$(TARGET_NAME)"; 557 | SWIFT_VERSION = 5.0; 558 | TARGETED_DEVICE_FAMILY = "1,2"; 559 | TEST_TARGET_NAME = PinYinSwiftDemo; 560 | }; 561 | name = Debug; 562 | }; 563 | 6E32E7D7259E12D600EAB42C /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 567 | CODE_SIGN_STYLE = Automatic; 568 | INFOPLIST_FILE = PinYinSwiftDemoUITests/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = ( 570 | "$(inherited)", 571 | "@executable_path/Frameworks", 572 | "@loader_path/Frameworks", 573 | ); 574 | PRODUCT_BUNDLE_IDENTIFIER = hlc.com.RunLoopDemo.PinYinSwiftDemoUITests; 575 | PRODUCT_NAME = "$(TARGET_NAME)"; 576 | SWIFT_VERSION = 5.0; 577 | TARGETED_DEVICE_FAMILY = "1,2"; 578 | TEST_TARGET_NAME = PinYinSwiftDemo; 579 | }; 580 | name = Release; 581 | }; 582 | /* End XCBuildConfiguration section */ 583 | 584 | /* Begin XCConfigurationList section */ 585 | 6E32E7A0259E12D300EAB42C /* Build configuration list for PBXProject "PinYinSwiftDemo" */ = { 586 | isa = XCConfigurationList; 587 | buildConfigurations = ( 588 | 6E32E7CD259E12D600EAB42C /* Debug */, 589 | 6E32E7CE259E12D600EAB42C /* Release */, 590 | ); 591 | defaultConfigurationIsVisible = 0; 592 | defaultConfigurationName = Release; 593 | }; 594 | 6E32E7CF259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemo" */ = { 595 | isa = XCConfigurationList; 596 | buildConfigurations = ( 597 | 6E32E7D0259E12D600EAB42C /* Debug */, 598 | 6E32E7D1259E12D600EAB42C /* Release */, 599 | ); 600 | defaultConfigurationIsVisible = 0; 601 | defaultConfigurationName = Release; 602 | }; 603 | 6E32E7D2259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemoTests" */ = { 604 | isa = XCConfigurationList; 605 | buildConfigurations = ( 606 | 6E32E7D3259E12D600EAB42C /* Debug */, 607 | 6E32E7D4259E12D600EAB42C /* Release */, 608 | ); 609 | defaultConfigurationIsVisible = 0; 610 | defaultConfigurationName = Release; 611 | }; 612 | 6E32E7D5259E12D600EAB42C /* Build configuration list for PBXNativeTarget "PinYinSwiftDemoUITests" */ = { 613 | isa = XCConfigurationList; 614 | buildConfigurations = ( 615 | 6E32E7D6259E12D600EAB42C /* Debug */, 616 | 6E32E7D7259E12D600EAB42C /* Release */, 617 | ); 618 | defaultConfigurationIsVisible = 0; 619 | defaultConfigurationName = Release; 620 | }; 621 | /* End XCConfigurationList section */ 622 | }; 623 | rootObject = 6E32E79D259E12D300EAB42C /* Project object */; 624 | } 625 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/project.xcworkspace/xcuserdata/hlc.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hlc0000/PinYinSwift/3c52e3e27b3c4f87234143c52f9deb55a11afee5/PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/project.xcworkspace/xcuserdata/hlc.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo.xcodeproj/xcuserdata/hlc.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PinYinSwiftDemo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PinYinSwiftDemo 4 | // 5 | // Created by hlc on 2020/12/31. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 29 | // Called when the user discards a scene session. 30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 32 | } 33 | 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/PinYinSwift/String+filtering.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+filtering.swift 3 | // SearchSwift 4 | // 5 | // Created by hlc on 2020/12/28. 6 | // 7 | 8 | import Foundation 9 | 10 | extension String{ 11 | /** 12 | 去掉首尾空格 13 | */ 14 | var removeHeadAndTailSpace:String{ 15 | let whitespace = CharacterSet.whitespaces 16 | return self.trimmingCharacters(in: whitespace) 17 | } 18 | 19 | /** 20 | 去掉首尾空格 包括后面的换行\n 21 | */ 22 | var removeHeadAndTailSpacepro:String{ 23 | let whitespace = CharacterSet.whitespacesAndNewlines 24 | return self.trimmingCharacters(in: whitespace) 25 | } 26 | 27 | /** 28 | 去掉所有空格 29 | */ 30 | var removeAllSapce:String{ 31 | return self.replacingOccurrences(of: "", with: "", options: .literal, range: nil) 32 | } 33 | 34 | // Allows us to use String[index] notation 35 | subscript(i:Int) -> UniChar{ 36 | // return self[index(startIndex, offsetBy: i) 37 | return self.utf16[index(startIndex,offsetBy: i)] 38 | } 39 | 40 | //使用正则表达式替换 41 | func pregReplace(pattern: String , with: String , 42 | options: NSRegularExpression . Options = []) -> String { 43 | let regex = try! NSRegularExpression (pattern: pattern, options: options) 44 | return regex.stringByReplacingMatches( in : self , options: [], 45 | range: NSMakeRange (0, self .count), 46 | withTemplate: with) 47 | } 48 | 49 | func getSubString(fromIndex:Int,toLength:Int)->String{ 50 | let from_index = self.index(self.startIndex, offsetBy: fromIndex) 51 | let to_index = self.index(self.startIndex, offsetBy: toLength) 52 | let result = String(self[from_index.. Bool { 57 | for (_, value) in self.enumerated() { 58 | if ("\u{4E00}" <= value && value <= "\u{9FA5}") { 59 | return true 60 | } 61 | } 62 | return false 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/PinYinSwift/configuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // configuration.swift 3 | // SearchSwift 4 | // 5 | // Created by hlc on 2020/12/26. 6 | // 7 | 8 | import Foundation 9 | 10 | let MAXLENGTH = 4 11 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/PinYinSwift/contentFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // contentFormatter.swift 3 | // SearchSwift 4 | // 5 | // Created by hlc on 2020/12/26. 6 | // 7 | 8 | import Foundation 9 | 10 | class transformationModel{ 11 | var pinyinName:String = "" 12 | var model:AnyObject 13 | init(model:AnyObject) { 14 | self.model = model 15 | } 16 | } 17 | 18 | public class contentFormatter{ 19 | /** 20 | 传入一个[String],把数组中的所有的String转换为拼音 21 | isDefaultParticiple:true 使用最大匹配算法 false:使用系统API进行分词 22 | */ 23 | static func hanyuPinyinStringArray(array:Array,isDefaultParticiple:Bool=true)->[String]{ 24 | var stringArray = [String]() 25 | for object in array { 26 | if object == ""{ stringArray.append(object) 27 | continue } 28 | let pinyinResult = pinyinResource.hanyuToPinyin(content: object,isDefaultParticiple: isDefaultParticiple) 29 | stringArray.append(pinyinResult) 30 | } 31 | return stringArray 32 | } 33 | 34 | /** 35 | 传入一个[String],把数组中的所有的String转换为拼音 36 | isDefaultParticiple:true 使用最大匹配算法 false:使用系统API进行分词 37 | */ 38 | static func hanyuPinyinString(content:String,isDefaultParticiple:Bool=true)->String{ 39 | if content == ""{ return content } 40 | return pinyinResource.hanyuToPinyin(content: content,isDefaultParticiple: isDefaultParticiple) 41 | } 42 | 43 | /** 44 | 传入一个[AnyObject]并指定需要转为拼音的字段 45 | isDefaultParticiple:true 使用最大匹配算法 false:使用系统API进行分词 46 | return 返回一个包含拼音以及数据模型的数组 47 | */ 48 | static func hanyuPinyinAnyArray(array:Array,propertyName:String,isDefaultParticiple:Bool=true)->[transformationModel]?{ 49 | var transArray = [transformationModel]() 50 | for object in array { 51 | let transformation_model = transformationModel(model: object) 52 | guard let content = getValueOfProperty(object: object,propertyName: propertyName) else{ return nil } 53 | let pinyinResult = pinyinResource.hanyuToPinyin(content: content,isDefaultParticiple: isDefaultParticiple) 54 | transformation_model.pinyinName = pinyinResult 55 | transArray.append(transformation_model) 56 | } 57 | return transArray 58 | } 59 | 60 | static private func getValueOfProperty(object:AnyObject,propertyName:String)->String?{ 61 | var count: UInt32 = 0; 62 | let cls: AnyClass? = object_getClass(object); 63 | guard let propertys = class_copyPropertyList(cls, &count) else{ return nil } 64 | for index in 0..[String:String]?{ 19 | var pinyinTable:Dictionary? = [String:String](); 20 | if let resource_name = Bundle.main.url(forResource: resourceName, withExtension: extensionName){ 21 | let dictionaryText = try? String(contentsOf: resource_name,encoding: String.Encoding.utf8) 22 | autoreleasepool { 23 | if let lines = dictionaryText?.split(separator: "\r\n"){ 24 | for (_,obj) in lines.enumerated() { 25 | let lineComponents = obj.components(separatedBy: separated) 26 | var key = lineComponents[0] 27 | key = key.pregReplace(pattern: " ", with: "") 28 | let value = lineComponents[1] 29 | pinyinTable?[key] = value 30 | } 31 | } 32 | } 33 | } 34 | print("11111") 35 | return pinyinTable 36 | } 37 | 38 | /** 39 | 进行拼音转换 40 | content:需要转换的内容 41 | */ 42 | static var parContents = [String]() 43 | static func hanyuToPinyin(content:String,isDefaultParticiple:Bool)->String{ 44 | if termsToPinyinTable?.count == 0{ termsToPinyinTable = getPinyinRecordTable(resourceName: "unicode_sentenceto_pinyin", extensionName: "txt", separated: ":")} 45 | if charToPinyinTable?.count == 0{ charToPinyinTable = getPinyinRecordTable(resourceName: "unicode_to_hanyu_pinyin", extensionName: "txt", separated: " ")} 46 | if(isDefaultParticiple == true){ 47 | /** 48 | 使用最大分词算法 49 | */ 50 | let result = hanyuMaxParticiple(content: content) 51 | pinyinResult = result 52 | }else{ 53 | /**使用默认分词*/ 54 | parContents = hanyuDefaultParticiple(content: content) 55 | convert(index: 0) 56 | } 57 | return pinyinResult 58 | } 59 | 60 | /** 61 | 把分词好的数据转换为拼音 62 | */ 63 | static private func convert(index:Int){ 64 | var currentIndex = index 65 | let content = parContents[currentIndex] 66 | 67 | let result = getPinyinRecord(content: content) 68 | pinyinResult.append(result) 69 | currentIndex+=1 70 | if(currentIndex < parContents.count){ convert(index: currentIndex) } 71 | } 72 | 73 | /** 74 | 查找unicode_sentenceto_pinyin中对应数据,如果没有数据,返回nil 75 | */ 76 | static private func getTermsToPinyinRecord(content:String)->String?{ 77 | if let termsPinyin = termsToPinyinTable?[content]{ 78 | var resultPinyin = "" 79 | resultPinyin = termsPinyin.pregReplace(pattern: "[1-5]", with: "") 80 | resultPinyin = resultPinyin.pregReplace(pattern: " ", with: "") 81 | return resultPinyin 82 | } 83 | return nil 84 | } 85 | 86 | /** 87 | 单个文字转换拼音 88 | */ 89 | static private func getCharToPinyinRecord(content:String)->String?{ 90 | let unContent = content[0] 91 | let codepointHexStr = String(format: "%x", unContent).uppercased() 92 | let record = charToPinyinTable?[codepointHexStr] 93 | if let pinyinStr = record?.components(separatedBy: ","){ 94 | var pinyin = pinyinStr[0] 95 | pinyin = pinyin.pregReplace(pattern: "[1-5]", with: "") 96 | return pinyin 97 | } 98 | return nil 99 | } 100 | 101 | /** 102 | 使用系统API分词 103 | */ 104 | static private func hanyuDefaultParticiple(content:String)->[String]{ 105 | var contents = [String](); 106 | if content.count == 1{ contents.append(content) } 107 | var tempContent = "" 108 | let ref = CFStringTokenizerCreate(nil, content as CFString, CFRangeMake(0, content.count), kCFStringTokenizerUnitWord, nil) 109 | CFStringTokenizerAdvanceToNextToken(ref); 110 | var range = CFStringTokenizerGetCurrentTokenRange(ref) 111 | while range.length>0 { 112 | tempContent = content.getSubString(fromIndex: range.location, toLength: range.location + range.length) 113 | contents.append(tempContent) 114 | CFStringTokenizerAdvanceToNextToken(ref) 115 | range = CFStringTokenizerGetCurrentTokenRange(ref) 116 | } 117 | return contents 118 | } 119 | 120 | 121 | 122 | static private func getPinyinRecord(content:String)->String{ 123 | let resultPinyin = hanyuSubString(content: content,index: 0) 124 | return resultPinyin 125 | } 126 | 127 | static private func hanyuSubString(content:String,index:Int)->String{ 128 | var inLength = 1, currentIndex = index 129 | if(content.count > 1){ inLength = content.count} 130 | var result = "" 131 | autoreleasepool { 132 | while inLength > currentIndex { 133 | let tempContent = content.getSubString(fromIndex: currentIndex, toLength: inLength) 134 | if(tempContent.count == 1){ 135 | if let pinyin = getCharToPinyinRecord(content: tempContent){ 136 | currentIndex+=1 137 | inLength = content.count 138 | result.append(pinyin) 139 | continue 140 | } 141 | currentIndex+=1 142 | inLength = content.count 143 | result.append(tempContent) 144 | continue 145 | } 146 | if let pinyin = getTermsToPinyinRecord(content: tempContent){ 147 | currentIndex+=tempContent.count 148 | inLength = content.count 149 | result.append(pinyin) 150 | continue 151 | } 152 | 153 | if inLength-1 != currentIndex{ inLength -= 1 } 154 | } 155 | } 156 | return result 157 | } 158 | 159 | /** 160 | 使用最大分词算法 161 | */ 162 | static private func hanyuMaxParticiple(content:String)->String{ 163 | let result = pinSubString(content: content, index: 0) 164 | return result 165 | } 166 | 167 | static private func pinSubString(content:String,index:Int)->String{ 168 | var inLength = 1,currentIndex = index 169 | if content.count > MAXLENGTH{ inLength = MAXLENGTH } 170 | else{ inLength = content.count } 171 | var result = "" 172 | autoreleasepool { 173 | while inLength > currentIndex{ 174 | let tempContent = content.getSubString(fromIndex: currentIndex, toLength: inLength) 175 | if tempContent.count == 1{ 176 | if let pinyin = getCharToPinyinRecord(content: tempContent){ 177 | result.append(pinyin) 178 | currentIndex+=1 179 | if currentIndex + MAXLENGTH > content.count{ inLength = content.count } 180 | else{ inLength = MAXLENGTH + currentIndex } 181 | continue 182 | } 183 | result.append(tempContent) 184 | currentIndex+=1 185 | if currentIndex + MAXLENGTH > content.count{ inLength = content.count } 186 | else{ inLength = MAXLENGTH + currentIndex } 187 | continue 188 | } 189 | 190 | if let pinyin = getTermsToPinyinRecord(content: tempContent){ 191 | result.append(pinyin) 192 | currentIndex+=tempContent.count 193 | if currentIndex + MAXLENGTH > content.count{ inLength = content.count } 194 | else{ inLength = MAXLENGTH + currentIndex } 195 | } 196 | 197 | if inLength-1 != currentIndex{ inLength -= 1 } 198 | } 199 | } 200 | return result 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // PinYinSwiftDemo 4 | // 5 | // Created by hlc on 2020/12/31. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | } 21 | 22 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PinYinSwiftDemo 4 | // 5 | // Created by hlc on 2020/12/31. 6 | // 7 | 8 | import UIKit 9 | 10 | @objcMembers class provincialCapital:NSObject { 11 | var cityName = "" 12 | var imgString = "" 13 | } 14 | 15 | class ViewController: UIViewController { 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view. 20 | 21 | let stringArray = ["济南","石家庄","长春","哈尔滨","沈阳","呼和浩特","乌鲁木齐","兰州","银川","太原","西安","郑州","合肥","南京","杭州","福州","广州","南昌","海口","南宁","贵阳","长沙","武汉","成都","昆明","拉萨","西宁","天津","上海","重庆","北京","台北"] 22 | 23 | let queue = DispatchQueue(label: "queue") 24 | queue.async { 25 | let resultArray = contentFormatter.hanyuPinyinStringArray(array: stringArray) 26 | for object in resultArray { 27 | print(object) 28 | } 29 | } 30 | let content = contentFormatter.hanyuPinyinString(content: "春运多地机票价格远低于火车票",isDefaultParticiple: true) 31 | print(content) 32 | 33 | var provCapiArray = [provincialCapital]() 34 | autoreleasepool { 35 | for index in 0.. 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemoTests/PinYinSwiftDemoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PinYinSwiftDemoTests.swift 3 | // PinYinSwiftDemoTests 4 | // 5 | // Created by hlc on 2020/12/31. 6 | // 7 | 8 | import XCTest 9 | @testable import PinYinSwiftDemo 10 | 11 | class PinYinSwiftDemoTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() throws { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PinYinSwiftDemo/PinYinSwiftDemoUITests/PinYinSwiftDemoUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PinYinSwiftDemoUITests.swift 3 | // PinYinSwiftDemoUITests 4 | // 5 | // Created by hlc on 2020/12/31. 6 | // 7 | 8 | import XCTest 9 | 10 | class PinYinSwiftDemoUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PinYinSwift 2 | 3 | `PinYinSwift`是一款基于词库的汉字转换拼音的小工具。 4 | 5 | 特性: 6 | ============== 7 | 8 | - 通过词库最大匹配方式进行转换,尽量提高多音字转换准确率。 9 | - 用户可以通过`isDefaultParticiple`这个字段设置为`false`使用系统分词方式进行转换。 10 | - 单个汉字转换通过生成汉字编码方式进行匹配。 11 | 12 | 13 | 关于多音字说明: 14 | ------------------------------------------------------------- 15 | 想要准确得识别每一条语句中的多音字有两个关键因素,一个是能否准确得给语句进行分词,还有一个就是我们的词库的丰富程度。 16 | 17 | 示例: 18 | ------------------------------ 19 | 直接传入一个需要转换的String 20 | 21 | ``` 22 | let content = contentFormatter.hanyuPinyinString(content: "你的人生格言是什么?") 23 | 24 | let content = contentFormatter.hanyuPinyinString(content: "你的人生格言是什么?",isDefaultParticiple: true) 25 | 26 | ``` 27 | 28 | 传入一个字符串数组 29 | 30 | ``` 31 | let stringArray = ["济南","石家庄","长春","哈尔滨","沈阳","呼和浩特","乌鲁木齐","兰州","银川","太原","西安","郑州","合肥","南京","杭州","福州","广州","南昌","海口","南宁","贵阳","长沙","武汉","成都","昆明","拉萨","西宁","天津","上海","重庆","北京","台北"] 32 | 33 | let queue = DispatchQueue(label: "queue") 34 | queue.async { 35 | let resultArray = contentFormatter.hanyuPinyinStringArray(array: stringArray) 36 | for object in resultArray { 37 | print(object) 38 | } 39 | } 40 | 41 | ``` 42 | 43 | 传入一个模型数组类型,并且指定要转换为拼音的属性名称,内部会创建一个transformationModel对象,并且把外部传递进来的模型数组中的模型作为transformationModel中的一个属性 44 | 45 | ``` 46 | @objcMembers class provincialCapital:NSObject { 47 | var cityName = "" 48 | var imgString = "" 49 | } 50 | ``` 51 | 52 | ``` 53 | var provCapiArray = [provincialCapital]() 54 | autoreleasepool { 55 | for index in 0..