cocoa_chen

iOS开发笔记 第二篇

2016-04-21

目录

  • dispatch_group_enter和dispatch_group_leave
  • 如何获取statusbar的高度
  • UILabel在iOS8.X系统上高度为0时显示一部分的解决办法
  • 如何判断子类是否复写了父类的方法

1. dispatch_group_enter()和dispatch_group_leave()

在平时的开发需求中,经常会遇到需要将几项操作执行完毕之后再执行最后的completion,使用GCD的group便可满足我们的需求,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"action 1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"action 2");
});
//通知主线程刷新UI或者执行其他操作
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"finish");
});

当然还有另外一种情况,当要执行的操作不是用dispatch_group_async来实现而是采用async的block回调时(比如使用AFNetworking的网络请求操作),上面的代码就不太合适了,此时可以使用dispatch_group_enter()和dispatch_group_leave()来解决,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dispatch_group_t group = dispatch_group_create();
//请求动态信息
dispatch_group_enter(group);
[self fetchFeedInfoWithCompletion:^(NSDictionary *feed, NSError *error) {
//do something with FeedInfo
dispatch_group_leave(group);
}];
//请求评论信息
dispatch_group_enter(group);
[self fetchCommentsWithCompletion:^(NSDictionary *feed, NSError *error) {
//do something with Comments
dispatch_group_leave(group);
}];
//上面的请求都执行完毕之后在主线程刷新UI
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//刷新UI等
//reloadData...
});

上面的代码中notify的block代码会在fetchFeedInfoWithCompletion和fetchCommentsWithCompletion的block回调之后在执行。需要注意的问题是dispatch_group_enter()dispatch_group_leave()总是成对出现的,如果少写了dispatch_group_leave()会导致dispatch_group_notify的block不会执行;如果少写了dispatch_group_enter()则会导致程序崩溃。

2.如何获取statusbar的高度:

示例代码如下:

1
2
3
4
5
CGFloat AACStatusBarHeight()
{
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
return MIN(statusBarSize.width, statusBarSize.height);
}

参考链接:http://stackoverflow.com/questions/26036744/display-status-bar-on-landscape-orientation-for-ios-8

3.UILabel在iOS8.X系统上高度为0时显示一部分的解决办法

UILabel在iOS8.X系统上高度为0时仍然会显示中间的某一部分,而在iOS7.X和iOS9.X系统上则没有这个问题,应该是Apple的一个bug,示例代码以及在iOS8.X上的效果如下所示:

1
2
3
4
5
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 0)];  //为了测试,设置高度为0
label.backgroundColor = [UIColor blueColor]; //高度为0时背景色并不会显示,这里为了明显设置为蓝色
label.textColor = [UIColor blackColor];
label.text = @"测试";
[self.view addSubview:label];

解决办法有两种:手动设置label的clipsToBounds为YES,或者当高度为0时hidden掉label。代码如下:

1
2
label.clipsToBounds = YES;
//label.hidden = YES; //高度为0时hidden掉

4.如何判断子类是否复写了父类的方法

以前用Runtime实现过判断子类是否复写父类方法的功能,今天在阅读UITableView-FDTemplateLayoutCell的源码时发现了一种更方便的判断方法,逻辑如下:

首先创建两个类,Person类继承自NSObject;我的码农Coder类继承自Person,同时在Person类中定义doSomething的方法,如下所示:

1
2
3
4
5
6
7
8
9
@interface Person : NSObject

- (void)doSomething;

@end

@interface Coder : Person

@end

接着在单元测试中实现判断,主要逻辑是子类对象不是由父类创建以及判断子类调用方法的IMP和父类调用方法的IMP是否一致,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)test_inheritedAndOverrided
{
//判断子类是否复写了父类的方法
Coder *coder = [Coder new];
SEL selector = @selector(doSomething);
BOOL inherited = ![coder isMemberOfClass:[Person class]]; //判断对象不是由父类本身创建的
BOOL overrided = [coder.class instanceMethodForSelector:selector] != [Person instanceMethodForSelector:selector]; //判断同一个方法,子类调用的IMP跟父类调用的IMP是否一致,如果不一致则说明子类复写了父类的方法
if (inherited && overrided) {
NSLog(@"子类复写了父类的方法");
}else{
NSLog(@"子类没有复写父类的方法");
}
XCTAssertTrue(inherited);
XCTAssertTrue(overrided);
}

如果子类Coder类中复写了doSomething方法,单元测试会通过;如果没有则说明子类没有复写父类的方法

参考代码:https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

Tags: iOS
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章