├── .gitignore ├── LICENSE ├── README.md ├── XC.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── XC ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── XCTests ├── Info.plist └── XCTests.m └── XCUITests ├── Info.plist └── XCUITests.m /.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) 2017 wangzhengang 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XCTest 2 | iOS自动化单元测试示例 3 | 4 | ## 一、前言: ## 5 | UITest的单元测试能最大限度的解放测试妹妹的双手,当然也会给程序员带来巨大工作量,完整的测试代码估计是项目代码的两倍,另外大家可以自行百度 Xcode Coverage 查看测试代码覆盖率,这篇文章只讲如何在工程中用XCTest框架做单元测试。 6 | 其中主要介绍了,用六个按钮示意的UITests使用和性能测试、异步测试的。 7 | ## 二、创建工程: ## 8 | 先创建个名字为 XCTest 的示例工程: 9 | ![这里写图片描述](http://img.blog.csdn.net/20171125144804085?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 10 | 这里要说明一下如果当初创建工程时未勾选上`Include Unit Tests` 和 `Include UI Test` 这两个复选框,可在项目工程targets目录下手动创建 Tests 、UITests目标,如下图示例: 11 | ![这里写图片描述](http://img.blog.csdn.net/20171128160304181?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 12 | 13 | 然后选中“iOS”在搜索框里输入 test ,就能看到 “iOS UITesting Bundle”和 “iOS Unit Testing Bundle”两个图标了,选中后点击“Next”按钮后,就能在 TARGET 目录下看到我们创建的测试项了。 14 | 15 | ![这里写图片描述](http://img.blog.csdn.net/20171128160328272?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 16 | 17 | ## 三、代码解释: ## 18 | **1、接下来看看具体代码:** 19 | 我们可以在 XCTests.m XCUITests.m 中发现一些共同的方法: 20 | 21 | ``` 22 | - (void)setUp { … } 23 | ``` 24 | 25 | ``` 26 | - (void)tearDown { … } 27 | ``` 28 | 29 | **2、方法的意义:** 30 | 将要开始执行测试代码时调用: `- (void)setUp { … }` , 31 | 测试代码执行完后调用,测试失败不调用: `- (void)tearDown { … }`, 32 | 其他任何方法都会在 `- (void)setUp` 和 `- (void)tearDown` 调用。 33 | 所有的测试类类名都以Tests结尾,同样类中所有的测试方法也都以`- (void)test` 开头。 34 | 35 | **3、获取app启动对象:** 36 | ``` 37 | [[[XCUIApplication alloc] init] launch];///为app对象分配内存并启动它 38 | ``` 39 | 40 | **4、其他:** 41 | UI测试示例代码: 42 | 43 | ``` 44 | XCUIElement *button1 = [[XCUIApplication alloc] init].buttons[@"1111"];///获取名字为2222的按钮 45 | XCTAssertTrue(button1.exists, @"'1111'按钮存在");///#值为true才能通过,为false会停在这里 46 | [button1 tap];///触发按钮的点击事件 47 | ``` 48 | 49 | 性能测试示例代码: 50 | ``` 51 | NSLog(@"性能测试"); 52 | [self measureBlock:^{ ///#用来分析代码执行的时间,log会打印在 console 里,同时本地也会有一份日志 53 | //实例化测试对象 54 | ///#测试那个类里的方法就要引入那个类 55 | ViewController *vc = [[ViewController alloc] init]; 56 | //#调用测试方法获取测试结果 57 | [vc performanceExample]; 58 | }]; 59 | 60 | 61 | ``` 62 | 异步测试示例代码: 63 | 注意其中的“执行顺序1、2、3、4” 64 | ``` 65 | XCTestExpectation *expectation = [self expectationWithDescription:@"百度翻译 测试"]; 66 | NSLog(@"执行顺序:1"); 67 | ///请求参数 68 | NSMutableDictionary *paramer = [NSMutableDictionary dictionary]; 69 | [paramer setValue:@"apple" forKey:@"q"]; 70 | [paramer setValue:@"en" forKey:@"from"]; 71 | [paramer setValue:@"zh" forKey:@"to"]; 72 | [paramer setValue:@"2015063000000001" forKey:@"appid"]; 73 | [paramer setValue:@"1435660288" forKey:@"salt"]; 74 | [paramer setValue:@"f89f9594663708c1605f3d736d01d2d4" forKey:@"sign"]; 75 | ///开始请求 76 | [ViewController networkRequestWithAPI:@"https://api.fanyi.baidu.com/api/trans/vip/translate" requestMethod:@"POST" cachePolicy:NSURLRequestUseProtocolCachePolicy requestParamer:paramer Completion:^(NSDictionary * _Nullable result, NSURLResponse * _Nullable response, NSError * _Nullable error) { 77 | 78 | [expectation fulfill];///调用fulfill后 waitForExpectationsWithTimeout 会结束等待 79 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 80 | XCTAssertTrue(httpResponse.statusCode==200, @"接口请求成功");///200表明http请求成功,请求失败会停在这里 81 | XCTAssertNotNil(result, @"json 对象不为空");///result结果为nil,会停在这里 82 | XCTAssertNil(error, @"请求没有出错");//error 不为nil,会停在这里 83 | NSLog(@"执行顺序:3"); 84 | }]; 85 | NSLog(@"执行顺序:2"); 86 | ///因为接口设置的是30秒超时,所以这里也设置30秒,意思就是这个线程最多等待30秒, 87 | [self waitForExpectationsWithTimeout:30.f handler:^(NSError * _Nullable error) { 88 | NSLog(@"执行顺序:4"); 89 | if (error) { 90 | ///测试代码无异常 91 | } else { 92 | ///测试代码有异常 93 | } 94 | }]; 95 | ``` 96 | 97 | ![这里写图片描述](http://img.blog.csdn.net/20171125150219470?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 98 | 99 | ![这里写图片描述](http://img.blog.csdn.net/20171125151009559?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 100 | 101 | ![这里写图片描述](http://img.blog.csdn.net/20171125151115126?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 102 | 103 | ## 四、图标解释: ## 104 | 105 | **1、测试前的图标:** 106 | ![这里写图片描述](http://img.blog.csdn.net/20171125152016034?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 这个图标出现在所有以 `- (void)test` 开头的方法前,这个是将要开始测试前的按钮状态图标,一旦点击就开始测试这个方法里的内容,或者我们也可以通过 *command+U* 的快捷键启动完整测试,完整测试会执行 Tests 和 UITests 下所有的测试类和类中所有的测试方法。 107 | 108 | **2、测试成功图标:** 109 | ![这里写图片描述](http://img.blog.csdn.net/20171125152821571?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 110 | 绿色代表测试成功,同时xcode 也会弹框提示, 111 | ![这里写图片描述](http://img.blog.csdn.net/20171125152910929?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 112 | 113 | **3、测试失败:** 114 | ![这里写图片描述](http://img.blog.csdn.net/20171125152953328?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 115 | 表示某个测试方法测试失败,同时进程也会停在测试未通过的代码那。 116 | ![这里写图片描述](http://img.blog.csdn.net/20171125153105074?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 117 | 118 | **4、录制代码:** 119 | XCode为了方便我们进行自动化单元测试真是费劲了心思,当我们把鼠标光标放到 `-(void)testXXX {....}` 这种测试方法里后,能在XCode的工具条上看到红色的按钮,这个红色的按钮就是用来录制代码。我们点击这个红色按钮后就会开始录制代码,我们在app里做任何操作都会在这里产生测试代码。 120 | ![这里写图片描述](http://img.blog.csdn.net/20171128161649162?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhlbmdhbmcwMDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 121 | app越复杂,录制代码时对电脑性能消耗就越高,一般8个G内存的苹果电脑都很卡,甚至会让 XCode 崩溃掉。我觉得录制代码只适合帮助我们寻找app页面上某个按钮或者其他view,而关于这个按钮或view的其他测试代码,需要我们手动去写。 122 | 123 | ## 五、断言注释: ## 124 | 125 | ``` 126 | XCTFail(format…) //生成一个失败的测试; 127 | XCTFail(@”Fail”); 128 | 129 | XCTAssertNil(a1, format…) //为空判断, a1 为空时通过,反之不通过; 130 | XCTAssertNil(@”not nil string”, @”string must be nil”); 131 | 132 | XCTAssertNotNil(a1, format…) //不为空判断,a1不为空时通过,反之不通过; 133 | XCTAssertNotNil(@”not nil string”, @”string can not be nil”); 134 | 135 | XCTAssert(expression, format…) //当expression求值为TRUE时通过; 136 | XCTAssert((2 > 2), @”expression must be true”); 137 | 138 | XCTAssertTrue(expression, format…) //当expression求值为TRUE时通过; 139 | XCTAssertTrue(1, @”Can not be zero”); 140 | 141 | XCTAssertFalse(expression, format…) //当expression求值为False时通过; 142 | XCTAssertFalse((2 < 2), @”expression must be false”); 143 | 144 | XCTAssertEqualObjects(a1, a2, format…) //判断相等, [a1 isEqual:a2] 值为TRUE时通过,其中一个不为空时,不通过; 145 | XCTAssertEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return YES”); 146 | XCTAssertEqualObjects(@”1″, @”2″, @”[a1 isEqual:a2] should return YES”); 147 | 148 | XCTAssertNotEqualObjects(a1, a2, format…) //判断不等, [a1 isEqual:a2] 值为False时通过, 149 | XCTAssertNotEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return NO”); 150 | XCTAssertNotEqualObjects(@”1″, @”2″, @”[a1 isEqual:a2] should return NO”); 151 | 152 | XCTAssertEqual(a1, a2, format…) //判断相等(当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以); 153 | XCTAssertNotEqual(a1, a2, format…) //判断不等(当a1和a2是 C语言标量、结构体或联合体时使用); 154 | 155 | XCTAssertEqualWithAccuracy(a1, a2, accuracy, format…) 判断相等,(double或float类型)//提供一个误差范围,当在误差范围(+/- accuracy )以内相等时通过测试; 156 | XCTAssertEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return YES”); 157 | 158 | XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format…) 判断不等,(double或float类型)//提供一个误差范围,当在误差范围以内不等时通过测试; 159 | XCTAssertNotEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return NO”); 160 | 161 | XCTAssertThrows(expression, format…) //异常测试,当expression发生异常时通过;反之不通过; 162 | XCTAssertThrowsSpecific(expression, specificException, format…) //异常测试,当expression发生 specificException 异常时通过;反之发生其他异常或不发生异常均不通过; 163 | XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format…) //异常测试,当expression发生具体异常、具体异常名称的异常时通过测试,反之不通过; 164 | XCTAssertNoThrow(expression, format…) //异常测试,当expression没有发生异常时通过测试; 165 | XCTAssertNoThrowSpecific(expression, specificException, format…)//异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过; 166 | XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format…) //异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过; 167 | 168 | 169 | //下面介绍一下测试元素的语法 170 | 171 | XCUIApplication: 172 | //继承XCUIElement,这个类掌管应用程序的生命周期,里面包含两个主要方法 173 | launch(): 174 | //启动程序 175 | terminate() 176 | //终止程序 177 | 178 | XCUIElement 179 | //继承NSObject,实现协议XCUIElementAttributes, XCUIElementTypeQueryProvider 180 | //可以表示系统的各种UI元素 181 | .exist 182 | //可以让你判断当前的UI元素是否存在,如果对一个不存在的元素进行操作,会导致测试组件抛出异常并中断测试 183 | descendantsMatchingType(type:XCUIElementType)->XCUIElementQuery 184 | //取某种类型的元素以及它的子类集合 185 | childrenMatchingType(type:XCUIElementType)->XCUIElementQuery 186 | //取某种类型的元素集合,不包含它的子类 187 | 188 | //这两个方法的区别在于,你仅使用系统的UIButton时,用childrenMatchingType就可以了,如果你还希望查询自己定义的子Button,就要用descendantsMatchingType 189 | 190 | //另外UI元素还有一些交互方法 191 | tap() 192 | //点击 193 | doubleTap() 194 | //双击 195 | pressForDuration(duration: NSTimeInterval) 196 | //长按一段时间,在你需要进行延时操作时,这个就派上用场了 197 | swipeUp() 198 | //这个响应不了pan手势,暂时没发现能用在什么地方,也可能是beta版的bug,先不解释 199 | typeText(text: String) 200 | //用于textField和textView输入文本时使用,使用前要确保文本框获得输入焦点,可以使用tap()函数使其获得焦点 201 | 202 | XCUIElementAttributes协议 203 | //里面包含了UIAccessibility中的部分属性 204 | ``` 205 | 206 | ## 五、结尾:## 207 | 如果大家觉得这篇文章和示例工程代码有用的话,点个赞,在github 上给个小星星,多谢。 208 | 博客地址:http://blog.csdn.net/zhengang007/ 209 | -------------------------------------------------------------------------------- /XC.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E63AEE251FC921B000A1D595 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E63AEE241FC921B000A1D595 /* AppDelegate.m */; }; 11 | E63AEE281FC921B000A1D595 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E63AEE271FC921B000A1D595 /* ViewController.m */; }; 12 | E63AEE2B1FC921B000A1D595 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E63AEE291FC921B000A1D595 /* Main.storyboard */; }; 13 | E63AEE2D1FC921B000A1D595 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E63AEE2C1FC921B000A1D595 /* Assets.xcassets */; }; 14 | E63AEE301FC921B000A1D595 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E63AEE2E1FC921B000A1D595 /* LaunchScreen.storyboard */; }; 15 | E63AEE331FC921B000A1D595 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E63AEE321FC921B000A1D595 /* main.m */; }; 16 | E63AEE3D1FC921B000A1D595 /* XCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E63AEE3C1FC921B000A1D595 /* XCTests.m */; }; 17 | E63AEE481FC921B000A1D595 /* XCUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E63AEE471FC921B000A1D595 /* XCUITests.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | E63AEE391FC921B000A1D595 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = E63AEE181FC921B000A1D595 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = E63AEE1F1FC921B000A1D595; 26 | remoteInfo = XC; 27 | }; 28 | E63AEE441FC921B000A1D595 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = E63AEE181FC921B000A1D595 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = E63AEE1F1FC921B000A1D595; 33 | remoteInfo = XC; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | E63AEE201FC921B000A1D595 /* XC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XC.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | E63AEE231FC921B000A1D595 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 40 | E63AEE241FC921B000A1D595 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 41 | E63AEE261FC921B000A1D595 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 42 | E63AEE271FC921B000A1D595 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 43 | E63AEE2A1FC921B000A1D595 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | E63AEE2C1FC921B000A1D595 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | E63AEE2F1FC921B000A1D595 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | E63AEE311FC921B000A1D595 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | E63AEE321FC921B000A1D595 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | E63AEE381FC921B000A1D595 /* XCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | E63AEE3C1FC921B000A1D595 /* XCTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XCTests.m; sourceTree = ""; }; 50 | E63AEE3E1FC921B000A1D595 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | E63AEE431FC921B000A1D595 /* XCUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XCUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | E63AEE471FC921B000A1D595 /* XCUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XCUITests.m; sourceTree = ""; }; 53 | E63AEE491FC921B000A1D595 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | E63AEE1D1FC921B000A1D595 /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | E63AEE351FC921B000A1D595 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | E63AEE401FC921B000A1D595 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | E63AEE171FC921B000A1D595 = { 82 | isa = PBXGroup; 83 | children = ( 84 | E63AEE221FC921B000A1D595 /* XC */, 85 | E63AEE3B1FC921B000A1D595 /* XCTests */, 86 | E63AEE461FC921B000A1D595 /* XCUITests */, 87 | E63AEE211FC921B000A1D595 /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | E63AEE211FC921B000A1D595 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | E63AEE201FC921B000A1D595 /* XC.app */, 95 | E63AEE381FC921B000A1D595 /* XCTests.xctest */, 96 | E63AEE431FC921B000A1D595 /* XCUITests.xctest */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | E63AEE221FC921B000A1D595 /* XC */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | E63AEE231FC921B000A1D595 /* AppDelegate.h */, 105 | E63AEE241FC921B000A1D595 /* AppDelegate.m */, 106 | E63AEE261FC921B000A1D595 /* ViewController.h */, 107 | E63AEE271FC921B000A1D595 /* ViewController.m */, 108 | E63AEE291FC921B000A1D595 /* Main.storyboard */, 109 | E63AEE2C1FC921B000A1D595 /* Assets.xcassets */, 110 | E63AEE2E1FC921B000A1D595 /* LaunchScreen.storyboard */, 111 | E63AEE311FC921B000A1D595 /* Info.plist */, 112 | E63AEE321FC921B000A1D595 /* main.m */, 113 | ); 114 | path = XC; 115 | sourceTree = ""; 116 | }; 117 | E63AEE3B1FC921B000A1D595 /* XCTests */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | E63AEE3C1FC921B000A1D595 /* XCTests.m */, 121 | E63AEE3E1FC921B000A1D595 /* Info.plist */, 122 | ); 123 | path = XCTests; 124 | sourceTree = ""; 125 | }; 126 | E63AEE461FC921B000A1D595 /* XCUITests */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | E63AEE471FC921B000A1D595 /* XCUITests.m */, 130 | E63AEE491FC921B000A1D595 /* Info.plist */, 131 | ); 132 | path = XCUITests; 133 | sourceTree = ""; 134 | }; 135 | /* End PBXGroup section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | E63AEE1F1FC921B000A1D595 /* XC */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = E63AEE4C1FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XC" */; 141 | buildPhases = ( 142 | E63AEE1C1FC921B000A1D595 /* Sources */, 143 | E63AEE1D1FC921B000A1D595 /* Frameworks */, 144 | E63AEE1E1FC921B000A1D595 /* Resources */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | ); 150 | name = XC; 151 | productName = XC; 152 | productReference = E63AEE201FC921B000A1D595 /* XC.app */; 153 | productType = "com.apple.product-type.application"; 154 | }; 155 | E63AEE371FC921B000A1D595 /* XCTests */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = E63AEE4F1FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XCTests" */; 158 | buildPhases = ( 159 | E63AEE341FC921B000A1D595 /* Sources */, 160 | E63AEE351FC921B000A1D595 /* Frameworks */, 161 | E63AEE361FC921B000A1D595 /* Resources */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | E63AEE3A1FC921B000A1D595 /* PBXTargetDependency */, 167 | ); 168 | name = XCTests; 169 | productName = XCTests; 170 | productReference = E63AEE381FC921B000A1D595 /* XCTests.xctest */; 171 | productType = "com.apple.product-type.bundle.unit-test"; 172 | }; 173 | E63AEE421FC921B000A1D595 /* XCUITests */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = E63AEE521FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XCUITests" */; 176 | buildPhases = ( 177 | E63AEE3F1FC921B000A1D595 /* Sources */, 178 | E63AEE401FC921B000A1D595 /* Frameworks */, 179 | E63AEE411FC921B000A1D595 /* Resources */, 180 | ); 181 | buildRules = ( 182 | ); 183 | dependencies = ( 184 | E63AEE451FC921B000A1D595 /* PBXTargetDependency */, 185 | ); 186 | name = XCUITests; 187 | productName = XCUITests; 188 | productReference = E63AEE431FC921B000A1D595 /* XCUITests.xctest */; 189 | productType = "com.apple.product-type.bundle.ui-testing"; 190 | }; 191 | /* End PBXNativeTarget section */ 192 | 193 | /* Begin PBXProject section */ 194 | E63AEE181FC921B000A1D595 /* Project object */ = { 195 | isa = PBXProject; 196 | attributes = { 197 | LastUpgradeCheck = 0910; 198 | ORGANIZATIONNAME = wangzhengang; 199 | TargetAttributes = { 200 | E63AEE1F1FC921B000A1D595 = { 201 | CreatedOnToolsVersion = 9.1; 202 | ProvisioningStyle = Automatic; 203 | }; 204 | E63AEE371FC921B000A1D595 = { 205 | CreatedOnToolsVersion = 9.1; 206 | ProvisioningStyle = Automatic; 207 | TestTargetID = E63AEE1F1FC921B000A1D595; 208 | }; 209 | E63AEE421FC921B000A1D595 = { 210 | CreatedOnToolsVersion = 9.1; 211 | ProvisioningStyle = Automatic; 212 | TestTargetID = E63AEE1F1FC921B000A1D595; 213 | }; 214 | }; 215 | }; 216 | buildConfigurationList = E63AEE1B1FC921B000A1D595 /* Build configuration list for PBXProject "XC" */; 217 | compatibilityVersion = "Xcode 8.0"; 218 | developmentRegion = en; 219 | hasScannedForEncodings = 0; 220 | knownRegions = ( 221 | en, 222 | Base, 223 | ); 224 | mainGroup = E63AEE171FC921B000A1D595; 225 | productRefGroup = E63AEE211FC921B000A1D595 /* Products */; 226 | projectDirPath = ""; 227 | projectRoot = ""; 228 | targets = ( 229 | E63AEE1F1FC921B000A1D595 /* XC */, 230 | E63AEE371FC921B000A1D595 /* XCTests */, 231 | E63AEE421FC921B000A1D595 /* XCUITests */, 232 | ); 233 | }; 234 | /* End PBXProject section */ 235 | 236 | /* Begin PBXResourcesBuildPhase section */ 237 | E63AEE1E1FC921B000A1D595 /* Resources */ = { 238 | isa = PBXResourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | E63AEE301FC921B000A1D595 /* LaunchScreen.storyboard in Resources */, 242 | E63AEE2D1FC921B000A1D595 /* Assets.xcassets in Resources */, 243 | E63AEE2B1FC921B000A1D595 /* Main.storyboard in Resources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | E63AEE361FC921B000A1D595 /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | E63AEE411FC921B000A1D595 /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | /* End PBXResourcesBuildPhase section */ 262 | 263 | /* Begin PBXSourcesBuildPhase section */ 264 | E63AEE1C1FC921B000A1D595 /* Sources */ = { 265 | isa = PBXSourcesBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | E63AEE281FC921B000A1D595 /* ViewController.m in Sources */, 269 | E63AEE331FC921B000A1D595 /* main.m in Sources */, 270 | E63AEE251FC921B000A1D595 /* AppDelegate.m in Sources */, 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | E63AEE341FC921B000A1D595 /* Sources */ = { 275 | isa = PBXSourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | E63AEE3D1FC921B000A1D595 /* XCTests.m in Sources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | E63AEE3F1FC921B000A1D595 /* Sources */ = { 283 | isa = PBXSourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | E63AEE481FC921B000A1D595 /* XCUITests.m in Sources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXSourcesBuildPhase section */ 291 | 292 | /* Begin PBXTargetDependency section */ 293 | E63AEE3A1FC921B000A1D595 /* PBXTargetDependency */ = { 294 | isa = PBXTargetDependency; 295 | target = E63AEE1F1FC921B000A1D595 /* XC */; 296 | targetProxy = E63AEE391FC921B000A1D595 /* PBXContainerItemProxy */; 297 | }; 298 | E63AEE451FC921B000A1D595 /* PBXTargetDependency */ = { 299 | isa = PBXTargetDependency; 300 | target = E63AEE1F1FC921B000A1D595 /* XC */; 301 | targetProxy = E63AEE441FC921B000A1D595 /* PBXContainerItemProxy */; 302 | }; 303 | /* End PBXTargetDependency section */ 304 | 305 | /* Begin PBXVariantGroup section */ 306 | E63AEE291FC921B000A1D595 /* Main.storyboard */ = { 307 | isa = PBXVariantGroup; 308 | children = ( 309 | E63AEE2A1FC921B000A1D595 /* Base */, 310 | ); 311 | name = Main.storyboard; 312 | sourceTree = ""; 313 | }; 314 | E63AEE2E1FC921B000A1D595 /* LaunchScreen.storyboard */ = { 315 | isa = PBXVariantGroup; 316 | children = ( 317 | E63AEE2F1FC921B000A1D595 /* Base */, 318 | ); 319 | name = LaunchScreen.storyboard; 320 | sourceTree = ""; 321 | }; 322 | /* End PBXVariantGroup section */ 323 | 324 | /* Begin XCBuildConfiguration section */ 325 | E63AEE4A1FC921B000A1D595 /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ALWAYS_SEARCH_USER_PATHS = NO; 329 | CLANG_ANALYZER_NONNULL = YES; 330 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 332 | CLANG_CXX_LIBRARY = "libc++"; 333 | CLANG_ENABLE_MODULES = YES; 334 | CLANG_ENABLE_OBJC_ARC = YES; 335 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_COMMA = YES; 338 | CLANG_WARN_CONSTANT_CONVERSION = YES; 339 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 340 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 341 | CLANG_WARN_EMPTY_BODY = YES; 342 | CLANG_WARN_ENUM_CONVERSION = YES; 343 | CLANG_WARN_INFINITE_RECURSION = YES; 344 | CLANG_WARN_INT_CONVERSION = YES; 345 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 349 | CLANG_WARN_STRICT_PROTOTYPES = YES; 350 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 351 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 352 | CLANG_WARN_UNREACHABLE_CODE = YES; 353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 354 | CODE_SIGN_IDENTITY = "iPhone Developer"; 355 | COPY_PHASE_STRIP = NO; 356 | DEBUG_INFORMATION_FORMAT = dwarf; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | ENABLE_TESTABILITY = YES; 359 | GCC_C_LANGUAGE_STANDARD = gnu11; 360 | GCC_DYNAMIC_NO_PIC = NO; 361 | GCC_NO_COMMON_BLOCKS = YES; 362 | GCC_OPTIMIZATION_LEVEL = 0; 363 | GCC_PREPROCESSOR_DEFINITIONS = ( 364 | "DEBUG=1", 365 | "$(inherited)", 366 | ); 367 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 368 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 369 | GCC_WARN_UNDECLARED_SELECTOR = YES; 370 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 371 | GCC_WARN_UNUSED_FUNCTION = YES; 372 | GCC_WARN_UNUSED_VARIABLE = YES; 373 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 374 | MTL_ENABLE_DEBUG_INFO = YES; 375 | ONLY_ACTIVE_ARCH = YES; 376 | SDKROOT = iphoneos; 377 | }; 378 | name = Debug; 379 | }; 380 | E63AEE4B1FC921B000A1D595 /* Release */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | ALWAYS_SEARCH_USER_PATHS = NO; 384 | CLANG_ANALYZER_NONNULL = YES; 385 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 386 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 387 | CLANG_CXX_LIBRARY = "libc++"; 388 | CLANG_ENABLE_MODULES = YES; 389 | CLANG_ENABLE_OBJC_ARC = YES; 390 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 391 | CLANG_WARN_BOOL_CONVERSION = YES; 392 | CLANG_WARN_COMMA = YES; 393 | CLANG_WARN_CONSTANT_CONVERSION = YES; 394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 395 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 396 | CLANG_WARN_EMPTY_BODY = YES; 397 | CLANG_WARN_ENUM_CONVERSION = YES; 398 | CLANG_WARN_INFINITE_RECURSION = YES; 399 | CLANG_WARN_INT_CONVERSION = YES; 400 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 401 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 404 | CLANG_WARN_STRICT_PROTOTYPES = YES; 405 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 406 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 407 | CLANG_WARN_UNREACHABLE_CODE = YES; 408 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 409 | CODE_SIGN_IDENTITY = "iPhone Developer"; 410 | COPY_PHASE_STRIP = NO; 411 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 412 | ENABLE_NS_ASSERTIONS = NO; 413 | ENABLE_STRICT_OBJC_MSGSEND = YES; 414 | GCC_C_LANGUAGE_STANDARD = gnu11; 415 | GCC_NO_COMMON_BLOCKS = YES; 416 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 417 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 418 | GCC_WARN_UNDECLARED_SELECTOR = YES; 419 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 420 | GCC_WARN_UNUSED_FUNCTION = YES; 421 | GCC_WARN_UNUSED_VARIABLE = YES; 422 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 423 | MTL_ENABLE_DEBUG_INFO = NO; 424 | SDKROOT = iphoneos; 425 | VALIDATE_PRODUCT = YES; 426 | }; 427 | name = Release; 428 | }; 429 | E63AEE4D1FC921B000A1D595 /* Debug */ = { 430 | isa = XCBuildConfiguration; 431 | buildSettings = { 432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 433 | CODE_SIGN_STYLE = Automatic; 434 | DEVELOPMENT_TEAM = 844L333N25; 435 | INFOPLIST_FILE = XC/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XC; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | TARGETED_DEVICE_FAMILY = "1,2"; 440 | }; 441 | name = Debug; 442 | }; 443 | E63AEE4E1FC921B000A1D595 /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 447 | CODE_SIGN_STYLE = Automatic; 448 | DEVELOPMENT_TEAM = 844L333N25; 449 | INFOPLIST_FILE = XC/Info.plist; 450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 451 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XC; 452 | PRODUCT_NAME = "$(TARGET_NAME)"; 453 | TARGETED_DEVICE_FAMILY = "1,2"; 454 | }; 455 | name = Release; 456 | }; 457 | E63AEE501FC921B000A1D595 /* Debug */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | BUNDLE_LOADER = "$(TEST_HOST)"; 461 | CODE_SIGN_STYLE = Automatic; 462 | DEVELOPMENT_TEAM = 844L333N25; 463 | INFOPLIST_FILE = XCTests/Info.plist; 464 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 465 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XCTests; 466 | PRODUCT_NAME = "$(TARGET_NAME)"; 467 | TARGETED_DEVICE_FAMILY = "1,2"; 468 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XC.app/XC"; 469 | }; 470 | name = Debug; 471 | }; 472 | E63AEE511FC921B000A1D595 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | BUNDLE_LOADER = "$(TEST_HOST)"; 476 | CODE_SIGN_STYLE = Automatic; 477 | DEVELOPMENT_TEAM = 844L333N25; 478 | INFOPLIST_FILE = XCTests/Info.plist; 479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 480 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XCTests; 481 | PRODUCT_NAME = "$(TARGET_NAME)"; 482 | TARGETED_DEVICE_FAMILY = "1,2"; 483 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XC.app/XC"; 484 | }; 485 | name = Release; 486 | }; 487 | E63AEE531FC921B000A1D595 /* Debug */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | CODE_SIGN_STYLE = Automatic; 491 | DEVELOPMENT_TEAM = 844L333N25; 492 | INFOPLIST_FILE = XCUITests/Info.plist; 493 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 494 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XCUITests; 495 | PRODUCT_NAME = "$(TARGET_NAME)"; 496 | TARGETED_DEVICE_FAMILY = "1,2"; 497 | TEST_TARGET_NAME = XC; 498 | }; 499 | name = Debug; 500 | }; 501 | E63AEE541FC921B000A1D595 /* Release */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | CODE_SIGN_STYLE = Automatic; 505 | DEVELOPMENT_TEAM = 844L333N25; 506 | INFOPLIST_FILE = XCUITests/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = com.etoury.XCUITests; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | TARGETED_DEVICE_FAMILY = "1,2"; 511 | TEST_TARGET_NAME = XC; 512 | }; 513 | name = Release; 514 | }; 515 | /* End XCBuildConfiguration section */ 516 | 517 | /* Begin XCConfigurationList section */ 518 | E63AEE1B1FC921B000A1D595 /* Build configuration list for PBXProject "XC" */ = { 519 | isa = XCConfigurationList; 520 | buildConfigurations = ( 521 | E63AEE4A1FC921B000A1D595 /* Debug */, 522 | E63AEE4B1FC921B000A1D595 /* Release */, 523 | ); 524 | defaultConfigurationIsVisible = 0; 525 | defaultConfigurationName = Release; 526 | }; 527 | E63AEE4C1FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XC" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | E63AEE4D1FC921B000A1D595 /* Debug */, 531 | E63AEE4E1FC921B000A1D595 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | E63AEE4F1FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XCTests" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | E63AEE501FC921B000A1D595 /* Debug */, 540 | E63AEE511FC921B000A1D595 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | E63AEE521FC921B000A1D595 /* Build configuration list for PBXNativeTarget "XCUITests" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | E63AEE531FC921B000A1D595 /* Debug */, 549 | E63AEE541FC921B000A1D595 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | /* End XCConfigurationList section */ 555 | }; 556 | rootObject = E63AEE181FC921B000A1D595 /* Project object */; 557 | } 558 | -------------------------------------------------------------------------------- /XC.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // XC 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. 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 | -------------------------------------------------------------------------------- /XC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // XC 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /XC/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /XC/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 | -------------------------------------------------------------------------------- /XC/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 | 28 | 38 | 48 | 58 | 68 | 78 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /XC/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /XC/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // XC 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | 15 | - (NSString *)md5HexDigest:(NSString*)input; 16 | 17 | 18 | - (void)performanceExample; 19 | 20 | 21 | 22 | 23 | ////网络请求 24 | + (void)networkRequestWithAPI:(NSString *)api requestMethod:(NSString *)method cachePolicy:(NSURLRequestCachePolicy)cachePolicy requestParamer:(NSDictionary *)paramer Completion:(void(^)(NSDictionary * _Nullable result, NSURLResponse * _Nullable response, NSError * _Nullable error))completion; 25 | 26 | 27 | 28 | 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /XC/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // XC 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import 11 | 12 | @interface ViewController () 13 | @property (weak, nonatomic) IBOutlet UILabel *staticTextLab; 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view, typically from a nib. 22 | } 23 | 24 | 25 | - (void)didReceiveMemoryWarning { 26 | [super didReceiveMemoryWarning]; 27 | // Dispose of any resources that can be recreated. 28 | } 29 | 30 | #pragma mark - button action 31 | 32 | - (IBAction)oneBtnAction:(UIButton *)sender { 33 | self.staticTextLab.text = @"你点击了 1111 按钮"; 34 | } 35 | 36 | - (IBAction)twoBtnAction:(UIButton *)sender { 37 | self.staticTextLab.text = @"你点击了 2222 按钮"; 38 | } 39 | - (IBAction)threeBtnAction:(UIButton *)sender { 40 | self.staticTextLab.text = @"你点击了 3333 按钮"; 41 | } 42 | - (IBAction)fourBtnAction:(UIButton *)sender { 43 | self.staticTextLab.text = @"你点击了 4444 按钮"; 44 | } 45 | - (IBAction)fiveBtnAction:(UIButton *)sender { 46 | self.staticTextLab.text = @"你点击了 5555 按钮"; 47 | } 48 | - (IBAction)sixBtnAction:(UIButton *)sender { 49 | self.staticTextLab.text = @"你点击了 6666 按钮"; 50 | } 51 | 52 | 53 | 54 | 55 | #pragma mark - 网络请求 56 | + (void)networkRequestWithAPI:(NSString *)api requestMethod:(NSString *)method cachePolicy:(NSURLRequestCachePolicy)cachePolicy requestParamer:(NSDictionary *)paramer Completion:(void(^)(NSDictionary * _Nullable result, NSURLResponse * _Nullable response, NSError * _Nullable error))completion { 57 | 58 | ///设置请求url 和 缓存方式 和 超时时间 59 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:api] cachePolicy:cachePolicy timeoutInterval:30]; 60 | ///设置请求方式 61 | [request setHTTPMethod:method]; 62 | ///设置内容格式 63 | [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; 64 | ///设置请求参数 65 | NSError *error = nil; 66 | NSData *paramerData = [NSJSONSerialization dataWithJSONObject:paramer options:NSJSONWritingPrettyPrinted error:&error]; 67 | if (error == nil) { 68 | [request setHTTPBody:paramerData]; 69 | } 70 | ///开始请求 71 | NSURLSession *session = [NSURLSession sharedSession]; 72 | NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 73 | if (error == nil && data) { 74 | ///json化数据 75 | NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; 76 | ///返回请求结果 77 | !completion?:completion(result, response, nil); 78 | } else { 79 | !completion?:completion(nil, nil, error); 80 | } 81 | }]; 82 | 83 | [dataTask resume]; 84 | } 85 | 86 | 87 | 88 | 89 | 90 | - (NSString *)md5HexDigest:(NSString*)input { 91 | const char *cStr = [input UTF8String]; 92 | unsigned char digest[CC_MD5_DIGEST_LENGTH * 2]; 93 | CC_MD5( cStr,(unsigned int)strlen(cStr), digest); 94 | NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 95 | for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) 96 | [result appendFormat:@"%02x", digest[i]]; 97 | return result; 98 | } 99 | 100 | 101 | 102 | - (void)performanceExample { 103 | NSInteger index = 0; 104 | for (NSInteger i =0 ; i < 1000000; ++i) { 105 | index++; 106 | } 107 | } 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /XC/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // XC 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. 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 | -------------------------------------------------------------------------------- /XCTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /XCTests/XCTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // XCTests.m 3 | // XCTests 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ViewController.h" 11 | 12 | @interface XCTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation XCTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | NSLog(@"test start"); ///#开始测试 22 | } 23 | 24 | - (void)tearDown { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | NSLog(@"test end");///#结束测试 28 | } 29 | 30 | ///# 其他任何方法都会在 - (void)setUp 和 - (void)tearDown 调用 31 | 32 | - (void)testFunc { 33 | NSLog(@"test func"); 34 | 35 | //实例化测试对象 36 | ViewController *vc = [[ViewController alloc] init]; 37 | //获取测试结果 38 | NSString *md5 = [vc md5HexDigest:@"123456"]; 39 | //使用断言测试 40 | XCTAssert(md5.length < 64, "字符串必须小于32");///#断言失败,测试过程就会停在这里 41 | } 42 | 43 | - (void)testPerformanceExample { 44 | NSLog(@"性能测试"); 45 | [self measureBlock:^{ ///#用来分析代码执行的时间,log会打印在 console 里,同时本地也会有一份日志 46 | //实例化测试对象 47 | ///#测试那个类里的方法就要引入那个类 48 | ViewController *vc = [[ViewController alloc] init]; 49 | //#调用测试方法获取测试结果 50 | [vc performanceExample]; 51 | }]; 52 | } 53 | 54 | 55 | - (void)testFanyiNetworkRequest { 56 | //// “执行顺序:” 表示代码执行顺序 57 | XCTestExpectation *expectation = [self expectationWithDescription:@"百度翻译 测试"]; 58 | NSLog(@"执行顺序:1"); 59 | ///请求参数 60 | NSMutableDictionary *paramer = [NSMutableDictionary dictionary]; 61 | [paramer setValue:@"apple" forKey:@"q"]; 62 | [paramer setValue:@"en" forKey:@"from"]; 63 | [paramer setValue:@"zh" forKey:@"to"]; 64 | [paramer setValue:@"2015063000000001" forKey:@"appid"]; 65 | [paramer setValue:@"1435660288" forKey:@"salt"]; 66 | [paramer setValue:@"f89f9594663708c1605f3d736d01d2d4" forKey:@"sign"]; 67 | ///开始请求 68 | [ViewController networkRequestWithAPI:@"https://api.fanyi.baidu.com/api/trans/vip/translate" requestMethod:@"POST" cachePolicy:NSURLRequestUseProtocolCachePolicy requestParamer:paramer Completion:^(NSDictionary * _Nullable result, NSURLResponse * _Nullable response, NSError * _Nullable error) { 69 | [expectation fulfill];///调用fulfill后 waitForExpectationsWithTimeout 会结束等待 70 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 71 | XCTAssertTrue(httpResponse.statusCode==200, @"接口请求成功");///200表明http请求成功,请求失败会停在这里 72 | XCTAssertNotNil(result, @"json 对象不为空");///result结果为nil,会停在这里 73 | XCTAssertNil(error, @"请求没有出错");//error 不为nil,会停在这里 74 | NSLog(@"执行顺序:3"); 75 | }]; 76 | NSLog(@"执行顺序:2"); 77 | ///因为接口设置的是30秒超时,所以这里也设置30秒,意思就是这个线程最多等待30秒, 78 | [self waitForExpectationsWithTimeout:30.f handler:^(NSError * _Nullable error) { 79 | NSLog(@"执行顺序:4"); 80 | }]; 81 | } 82 | 83 | 84 | 85 | 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /XCUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /XCUITests/XCUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // XCUITests.m 3 | // XCUITests 4 | // 5 | // Created by iron on 2017/11/25. 6 | // Copyright © 2017年 wangzhengang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XCUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation XCUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch];///为app对象分配内存并启动它 26 | 27 | // 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. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | ///UITest的测试代码能最大限度的解放测试妹妹的双手,当然也会给程序员带来巨大工作量,完整的测试代码估计是项目代码的两倍 37 | ///自行百度 Xcode Coverage 查看测试代码覆盖率 38 | 39 | 40 | ///这里的UItest代码最好自己写,录制完整测试代码在项目里不可行,毕竟项目的各种view层级是比较复杂的,会录出来一堆错误的代码,同时电脑也扛不住,Xcode会crash的。 41 | ///而完全靠自己写代码寻找XCUIElement也是很头疼的,view的层级复杂到山重水复疑无路, 42 | ///最好是,把录制测试代码的手段用在寻找XCUIElement上,而关于XCUIElement的其他tap()等事件代码最好自己写。 43 | ///如下示例,为了能寻找到textView我也是拼了,从window一路寻找下去,window儿子view的儿子view的儿子view的儿子view的儿子view的儿子view的view就是textView。 44 | // 示例 :XCUIElement *textView = [[[[[[[[app childrenMatchingType:XCUIElementTypeWindow] elementBoundByIndex:0] childrenMatchingType:XCUIElementTypeOther] elementBoundByIndex:1] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeTextView].element; 45 | 46 | 47 | 48 | XCUIElement *button1 = [[XCUIApplication alloc] init].buttons[@"1111"]; 49 | XCUIElement *button2 = [[XCUIApplication alloc] init].buttons[@"2222"];///获取名字为2222的按钮 50 | XCUIElement *button3 = [[XCUIApplication alloc] init].buttons[@"3333"]; 51 | XCUIElement *button4 = [[XCUIApplication alloc] init].buttons[@"4444"]; 52 | XCUIElement *button5 = [[XCUIApplication alloc] init].buttons[@"5555"]; 53 | XCUIElement *button6 = [[XCUIApplication alloc] init].buttons[@"6666"]; 54 | 55 | XCTAssertTrue(button1.exists, @"'1111'按钮存在");///#值为true才能通过,为false会停在这里 56 | XCTAssertTrue(button2.exists, @"'2222'按钮存在");///#值为true才能通过,为false会停在这里 57 | XCTAssertTrue(button3.exists, @"'3333'按钮存在");///#值为true才能通过,为false会停在这里 58 | XCTAssertTrue(button4.exists, @"'4444'按钮存在");///#值为true才能通过,为false会停在这里 59 | XCTAssertTrue(button5.exists, @"'5555'按钮存在");///#值为true才能通过,为false会停在这里 60 | XCTAssertTrue(button6.exists, @"'6666'按钮存在");///#值为true才能通过,为false会停在这里 61 | 62 | [button1 tap];///触发按钮的点击事件 63 | [button2 tap]; 64 | [button3 tap]; 65 | [button4 tap]; 66 | [button5 tap]; 67 | [button6 tap]; 68 | [button5 tap]; 69 | [button4 tap]; 70 | [button3 tap]; 71 | [button2 tap]; 72 | [button1 tap]; 73 | 74 | // Use recording to get started writing UI tests. 75 | // Use XCTAssert and related functions to verify your tests produce the correct results. 76 | } 77 | 78 | 79 | @end 80 | --------------------------------------------------------------------------------