/** testLoadPersonAsync 异步加载测试: 苹果的单元测试的特点:早期的单元测试并不好用! 1.是串行的: 1.1 先 setUp ---> 然后 test1 再 test2 再 test3 ...... 最后 tearDown 知道真相的我眼泪掉下来. */ #pragma mark - testLoadPersonAsync 异步加载测试 - (void)testLoadPersonAsync { //Xcode6.0之后进行了改进: //创建一个"预期"expectation: XCTestExpectation *expectation = [self expectationWithDescription:@"异步加载 Person"] ; [Person loadPersonAsync:^(Person *person) { NSLog(@"-_- --> %@ <-- -_-" , person.name) ; //标注预期达成: [expectation fulfill] ; }] ; //等待预期达成: //1.0f'之内预期达成我都认为是合理的: [self waitForExpectationsWithTimeout:1.0f handler:^(NSError * _Nullable error) { NSLog(@"哈哈哈 --> error = %@ <-- 哈哈哈" , error) ; }] ; } @end |
Person.h 文件
#import <Foundation/Foundation.h> @interface Person : NSObject //name: @property (nonatomic, copy) NSString *name ; //age: @property (nonatomic) NSInteger age ; //工厂方法: + (instancetype)personWithDictionary:(NSDictionary *)dictionary ; //异步加载个人记录:异步加载数据回调传值都是用的 block! //手写 block一定要注意格式: void (^) (Person *person)completion ; + (void)loadPersonAsync:(void (^) (Person *person))completion ; @end |
Person.m 文件
#import "Person.h" @implementation Person + (instancetype)personWithDictionary:(NSDictionary *)dictionary { //[[self alloc] init] ;这里用 self 是方便子类继承这个方法,在搞一个 person 的子类我就不用在写这个方法了! Person *obj = [[self alloc] init] ; //KVC 方法: [obj setValuesForKeysWithDictionary:dictionary] ; //为了防止单元测试时年龄非法: if (obj.age <= 0 || obj.age > 100) { obj.age = 0 ; } return obj ; } //写一个空方法:解决多一个 title : boss 的键值对的问题: - (void)setValue:(id)value forUndefinedKey:(NSString *)key { } + (void)loadPersonAsync:(void (^)(Person *))completion { dispatch_async(dispatch_get_global_queue(0, 0), ^{ [NSThread sleepForTimeInterval:1.0f] ; Person *person = [Person personWithDictionary:@{@"name":@"lisi" , @"age":@20}] ; dispatch_async(dispatch_get_main_queue(), ^{ //在 OC 中写块代码回调的时候一定要写块代码是否存在的判断条件,否则一出问题就会闪退: if (completion != nil) { //回调回来person 这个对象给我: completion(person) ; } }) ; }) ; } @end |